To master multithreading in Java, you must master various locks in Java and understand the use of thread pools in Java. For a summary of Java multithreading basics, refer to my blog post Java multithreading Summary (1) multithreading Basics
For more information, see http://www.cnblogs.com/zrtqsk/p/4104049.html.
I. Java locks
What is a lock. A lock is a mechanism to protect resources and prevent errors when multiple threads operate on resources at the same time.
Let's first look at the lock class diagram:
The locks in Java have two main root interfaces: Lock and ReadWriteLock, which respectively indicate the Lock and read/write Lock. The main implementation class of Lock is ReetrantLock. The main implementation class of ReadWriteLock is ReetrantReadWriteLock. The ReetrantReadWriteLock read and write locks are implemented through two internal classes: ReadLock and WriteLock, where ReadLock is a shared lock and WriteLock is an exclusive lock. Both internal classes implement the Lock interface.
(1)Java locks mainly have the following concepts:
1,Synchronization lock
At the same time, a synchronization lock can only be accessed by one thread. Based on objects and synchronized keywords are used for synchronization to achieve mutually exclusive access to competing resources.
2,Exclusive lock(Reentrant mutex lock)
Mutex, that is, at the same time point, can only be held by one thread; reentrant, that is, can be obtained multiple times by a single thread. What does it mean? According to the lock acquisition mechanism, it is divided"Fair lock" and "unfair lock". In Java, exclusive locks are implemented through ReentrantLock. The default value is unfair locks.
3,Fair lock
It is based on the first-come-first-served rule by the CLH wait thread. The thread queues in sequence and gets the lock fairly. It is an exclusive lock. In Java, ReetrantLock has a member variable Sync of the sync type. When its instance is of the FairSync type, ReetrantLock is a fair lock. Set sync to the FairSync type. Only -- Lock lock = new ReetrantLock (true) is required ).
4,Unfair lock
When the thread wants to obtain the lock, it will ignore the CLH waiting queue and directly obtain the lock. ReetrantLock is a non-fair Lock by default, or -- lock Lock = new ReetrantLock (false ).
5. Shared locks
Locks that can be acquired and shared by multiple threads at the same time. That is, multiple threads can obtain the lock and process the Lock Object. The typical read lock is ReentrantReadWriteLock. ReadLock. That is, multiple threads can read it without affecting the reading of it by other threads, but no one can modify it. CyclicBarrier, CountDownLatch, and Semaphore are also shared locks.
6,Read/write lock
A pair of related locks are maintained. The "read lock" is used for read-only operations. It is a "shared lock" and can be obtained by multiple threads at the same time. The write lock is used for write operations. It is an exclusive lock and can only be obtained by one thread lock. In Java, the read/write locks are defined as ReadWriteLock interfaces, and their implementation classes are ReentrantReadWriteLock, including internal classes ReadLock and WriteLock. Methods readLock () and writeLock () respectively return the lock of the Degree operation and the lock of the write operation.
(As for "deadlock", it is not a lock, but a state, that is, when two threads wait for each other to release the synchronization monitor, neither side can continue, resulting in a deadlock .)
The usage of the lock is mainly the following process:
// Get lock first. lock (); // then obtain the lock try {// various control operations} catch (Exception e) {} finally {lock. unlock (); // unlock}
As you can see, this usage is much easier than synchronized keyword Based on Object synchronization.
(2)LockSupport and Condition
1. LockSupport
Is the Basic thread blocking primitive used to create locks and other synchronization classes. The static methods park () and unpark () in LockSupport are used to block the thread and remove the blocking thread, without causing a deadlock. The demo is as follows:
Package lock; import java. util. concurrent. locks. lockSupport; public class LockSupportTest {static Thread mainThread = null; public static void main (String [] args) {// obtain the main Thread mainThread = Thread. currentThread (); // create a thread and start MyThread thread1 = new MyThread ("thread1"); thread1.start (); // simulate the thread to start System. out. println (Thread. currentThread (). getName () + "-----" runs now! "); For (int I = 0; I <5; I ++) {System. out. println (Thread. currentThread (). getName () + "-----" running step "+ I); // sleepOneSecond (); if (I = 2) {System. out. println (Thread. currentThread (). getName () + "-----" now pack main thread ---------- "); // block the main thread from LockSupport. park () ;}} System. out. println (Thread. currentThread (). getName () + "-----" run over! ");}/** Current Thread paused for one second */public static void sleepOneSecond () {try {Thread. sleep (1000);} catch (InterruptedException e) {// TODO Auto-generated catch block e. printStackTrace () ;}} static class MyThread extends Thread {public MyThread (String name) {super (name) ;}@ Override public void run () {synchronized (this) {// simulation starts System. out. println (Thread. currentThread (). getName () + "-----" runs now! "); For (int I = 0; I <5; I ++) {System. out. println (Thread. currentThread (). getName () + "-----" running step "+ I); // The current thread sleeps for 1 second sleepOneSecond () ;}// the simulated work ends. System. out. println (Thread. currentThread (). getName () + "-----" run over! ");} System. out. println (Thread. currentThread (). getName () + "-----" now unpack main thread -------- "); // remove the blocking LockSupport of the main thread. unpark (mainThread );}}}
The result is as follows:
thread1-----》 runs now!thread1-----》 running step 0main-----》 runs now!main-----》 running step 0thread1-----》 running step 1main-----》 running step 1main-----》 running step 2thread1-----》 running step 2main-----》 now pack main thread——————————thread1-----》 running step 3thread1-----》 running step 4thread1-----》 run over!thread1-----》 now unpack main thread———————— main-----》 running step 3main-----》 running step 4main-----》 run over!
2. Condition
The Lock can be precisely controlled to replace the wait, y, and policyall methods in the Object. It must be used together with the Lock. Await () and signal () can be used to sleep and wake up the thread. Creation Method: Condition condition = lock. newCondition ();
For more information about the demo, see http://www.cnblogs.com/skywang12345/p/3496716.html, as shown below:
Package LockSupportTest; import java. util. concurrent. locks. condition; import java. util. concurrent. locks. lock; import java. util. concurrent. locks. reentrantLock; public class ConditionTest {private static Lock lock = new ReentrantLock (); private static Condition condition = lock. newCondition (); public static void main (String [] args) {ThreadA ta = new ThreadA ("ta"); lock. lock (); // get the lock try {System. out. println (Thread. currentThread (). getName () + "start ta"); ta. start (); System. out. println (Thread. currentThread (). getName () + "block"); condition. await (); // wait for System. out. println (Thread. currentThread (). getName () + "continue");} catch (InterruptedException e) {e. printStackTrace ();} finally {lock. unlock (); // release lock} static class ThreadA extends Thread {public ThreadA (String name) {super (name) ;} public void run () {lock. lock (); // get the lock try {System. out. println (Thread. currentThread (). getName () + "wakup others"); condition. signal (); // wake up other threads on which the condition is locked} finally {lock. unlock (); // release the lock }}}}
The result is as follows:
main start tamain blockta wakup othersmain continue
As shown above, it is easy to use.
Ii. Thread Pool
Let's first look at the class diagram of the thread pool:
1. Introduction
It can be seen that the thread pool is mainly integrated by an Executor interface. This interface represents an executor and is used in a typical command mode. This interface only has one method void execute (Runnable command), submit and execute the task.
ExecuteService, as its name implies, refers to the Executor service class. It inherits the Executor interface and provides more detailed thread control methods.
AbstractExecutorService is an abstract class that implements most of the Methods of ExecutorService.
The most common ThreadPoolExecutor inherits the ExecutorService.
ForkJoinPool is the new thread pool of JDK 7 and inherits this thread class.
ScheduledExecutorService inherits the ExecutorService interface, which provides "latency" and "periodical execution" Features Compared with ExecutorService.
The ScheduledThreadPoolExecutor class implements the ScheduledExecutorService interface, inherits the ThreadPoolExecutor, and adds the "latency" and "periodical execution" features.
Executors is a factory class of a thread pool. It provides a series of static methods for creating thread pools or thread-related objects with different functions.
The basic usage of the thread pool is as follows:
// Create various threads Thread thread1 = new MyThread (); Thread thread2 = new MyThread (); Thread thread3 = new MyThread (); // create a thread pool // put the thread into the pool and execute pool.exe cute (thread1), pool.exe cute (thread2), pool.exe cute (thread3); // close the thread pool. shutdown ();
2. ForkJoinPool
It can be seen that the entire thread pool series, to put it bluntly, are three classes: ThreadPoolExecutor, ScheduledThreadPoolExecutor, and ForkJoinPool. One is a normal thread pool, and the other is a thread pool with the "latency" and "periodical execution" features added. So what is ForkJoinPool?
ForkJoinPool aims to solve the current and future multi-core computer problems. Other ExecuteService implementation classes are basically executed on a single core, solving the concurrency problem, while ForkJoinPool solves the parallel problem. In ExcuteService, tasks that are behind the job need to wait for the previous job to be executed before they can be executed. ForkJoinPool uses the work-stealing mode to help other threads execute the job. Work-stealing mode-All threads in the pool try to execute subtasks created by other threads, so that few threads are idle and efficient.
In addition to Runnable tasks, ForkJoinPool can also execute ForkJoinTask tasks. That is, the execute method of ForkJoinPool can pass in a ForkJoinTask object, which is different from Runnable, forkJoinTask is placed in the internal queue of the thread, while normal Runnable tasks are placed in the queue of the thread pool.
For more information about ForkJoinPool, see http://blog.csdn.net/aesop_wubo/article/details/10300273.
3. Executors
Executors is a factory class of a thread pool. It provides a series of static methods for creating thread pools or thread-related objects with different functions.
There are several static methods as follows:
NewCachedThreadPool (): Creates a thread pool with cache function. The system creates threads as needed and these threads are cached in the thread pool.
NewFixedThreadPool (int nThreads): Creates a reusable thread pool with a fixed number of threads.
NewSingleThreadExecutor (): Creates a thread pool with only one single thread.
NewScheduledThreadPool (int corePoolSize): Creates a thread pool with a specified number of threads. You can specify the latency to run the task. Even if the thread is idle, it is kept in the thread pool.
NewSingleThreadScheduledExecutor (): Creates a thread pool with only one thread. You can specify the latency to run the task.
4. Thread Pool status
The thread pool has five statuses: RUNNING, SHUTDOWN, STOP, TIDYING, and TERMINATED.
(Image Source: http://www.cnblogs.com/skywang12345/p/3509960.html)
RUNNING: When the thread pool is in the RUNNING state, it can receive new tasks and process the added tasks.
SHUTDOWN: When the thread pool is in the SHUTDOWN state, it does not receive new tasks, but can process the added tasks.
STOP: When the thread pool is in the STOP State, it does not receive new tasks, does not process added tasks, and interrupts the tasks being processed.
TIDYING: When all tasks have been terminated, the "number of tasks" recorded by ctl is 0, and the thread pool changes to the TIDYING status. When the thread pool changes to the TIDYING status, the hook function terminated () is executed (). Terminated () is empty in the ThreadPoolExecutor class. If you want to handle it when the thread pool changes to TIDYING, you can use the overload terminated () function.
TERMINATED: When the thread pool is completely TERMINATED, it becomes TERMINATED.
Reference: http://www.cnblogs.com/skywang12345/p/java_threads_category.html
Http://blog.csdn.net/aesop_wubo/article/details/10300273
If you think this article is not bad, please click to recommend it! Thank you!