Home  >  Article  >  Java  >  In-depth understanding of Java multi-threading principles: from scheduling mechanism to shared resource management

In-depth understanding of Java multi-threading principles: from scheduling mechanism to shared resource management

WBOY
WBOYOriginal
2024-02-22 23:42:03966browse

In-depth understanding of Java multi-threading principles: from scheduling mechanism to shared resource management

In-depth understanding of Java multi-threading principles: from scheduling mechanism to shared resource management

Introduction:
In modern computer application development, multi-threaded programming has become Common programming patterns. As a commonly used programming language, Java provides rich APIs and efficient thread management mechanisms in multi-threaded programming. However, a deep understanding of Java multithreading principles is crucial to writing efficient and reliable multithreaded programs. This article will explore the principles of Java multi-threading from scheduling mechanisms to shared resource management, and deepen understanding through specific code examples.

1. Scheduling mechanism:
In Java multi-threaded programming, the scheduling mechanism is the key to achieving concurrent execution. Java uses a preemptive scheduling strategy. When multiple threads run at the same time, the CPU will determine the time allocated to each thread based on factors such as priority, time slice, and thread waiting time.

The scheduling mechanism of Java threads can be controlled through the methods of the Thread class, such as thread priority settings, sleep and wake-up, etc. The following is a simple example:

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();
        thread1.setPriority(Thread.MIN_PRIORITY);
        thread2.setPriority(Thread.MAX_PRIORITY);
        thread1.start();
        thread2.start();
    }
}

In the above example, two thread objects are created, different priorities are set respectively, and then the threads are started through the start() method. Since the running order of threads is uncertain, the results of each run may be different.

2. Thread synchronization and mutual exclusion:
In multi-thread programming, there are access problems to shared resources. When multiple threads access a shared resource at the same time, problems such as race conditions and data inconsistencies may occur. Therefore, Java provides a variety of mechanisms to ensure thread synchronization and mutual exclusion of access to shared resources.

2.1 synchronized keyword:
The synchronized keyword can be used to modify methods or code blocks to provide safe access to shared resources in a multi-threaded environment. When a thread executes a synchronized method or accesses a synchronized code block, it will acquire the object's lock, and other threads need to wait for the lock to be released.

The following is a simple example:

class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();
        
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Count: " + counter.getCount());
    }
}

In the above example, a Counter class is defined, which contains a method to increment the count and get the count. Both methods are modified with the synchronized keyword to ensure safe access to the count variable. In the Main class, two threads are created to perform the operation of increasing the count respectively, and finally output the count result.

2.2 Lock interface:
In addition to the synchronized keyword, Java also provides the Lock interface and its implementation classes (such as ReentrantLock) to achieve thread synchronization and mutual exclusion. Compared with synchronized, the Lock interface provides more flexible thread control and can achieve more complex synchronization requirements.

The following is an example of using ReentrantLock:

class Counter {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    
    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();
        
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Count: " + counter.getCount());
    }
}

In the above example, the Counter class uses ReentrantLock to achieve synchronous access to the count variable. In the increment() and getCount() methods, acquire the lock by calling the lock() method, and then call the unlock() method in the finally block to release the lock.

3. Shared resource management:
In multi-threaded programming, the management of shared resources is the key to ensuring thread safety. Java provides a variety of mechanisms to manage shared resources, such as volatile keywords, atomic classes, etc.

3.1 volatile keyword:
The volatile keyword is used to modify shared variables to ensure that each read or write operates directly on the memory rather than reading or writing from the cache. Variables modified with the volatile keyword are visible to all threads.

The following is a simple example:

class MyThread extends Thread {
    private volatile boolean flag = false;
    
    public void stopThread() {
        flag = true;
    }
    
    @Override
    public void run() {
        while (!flag) {
            // do something
        }
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start();
        
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        thread.stopThread();
        
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

In the above example, the flag variable in the MyThread class is modified with the volatile keyword to ensure thread-safe stop. In the Main class, create a thread object, wait for one second after starting the thread, and then call the stopThread() method to stop the thread.

3.2 Atomic classes:
Java provides a series of atomic classes (such as AtomicInteger, AtomicLong), which can ensure thread-safe atomic operations and avoid race conditions.

The following is an example of using AtomicInteger:

class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();
    }
    
    public int getCount() {
        return count.get();
    }
}

public class Main {
    public static void main(String[] args) {
        Counter counter = new Counter();
        
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });
        
        thread1.start();
        thread2.start();
        
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println("Count: " + counter.getCount());
    }
}

In the above example, the Counter class uses AtomicInteger to ensure thread-safe counting. In the increment() method, the count is atomically incremented by calling the incrementAndGet() method.

Conclusion:
This article explores the principles of Java multi-threading in depth from the scheduling mechanism to shared resource management. Understanding the principles of Java multithreading is crucial to writing efficient and reliable multithreaded programs. Through the above code examples, readers can better understand the scheduling mechanism and shared resource management of Java multi-threading. At the same time, readers can also choose appropriate synchronization mechanisms and shared resource management methods according to actual needs to ensure the correctness and performance of multi-threaded programs.

The above is the detailed content of In-depth understanding of Java multi-threading principles: from scheduling mechanism to shared resource management. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn