History of Java multithreading

be born

The gene of Java comes from an internal project of Sun company in December 1990. The target device is household appliances, but the portability of C + + and the ease of use of API disgust programmers. In order to solve this problem, the oak language, the predecessor of Java, was. However, it was officially renamed Java in March 1995, which was the real birth of the Java language.

JDK 1.0

Jdk1 in January 1996 Version 0 has established the most basic thread model of Java from the beginning, and no substantive changes have taken place in the subsequent repair of this thread model, which can be said to be a good design with inheritance.

Preemptive and cooperative are two common process / thread scheduling methods. The operating system is very suitable to use preemptive scheduling to schedule its processes. It allocates time slices to different processes. For processes that are unresponsive for a long time, it has the ability to deprive its resources or even forcibly stop them. In a collaborative way, the process needs to consciously and actively release resources. In this scheduling mode, a thread with a long execution time may "starve" all other threads that need CPU. Java adopts the scheduling mode of hotspot virtual machine, which is preemptive call, so the Java language adopts preemptive thread scheduling from the beginning. The cooperative communication between threads in 1.0 adopts the simple and crude method of stop / resume / suspend. Stop stops all the remaining work in the run () method, including in the catch or finally statement, and throws a ThreadDeath exception (usually this exception does not need to be captured). Therefore, some cleaning work may not be completed, such as closing files, databases, etc., and all locks held by the modified thread will be released immediately, It will cause data interrupt synchronization and data inconsistency. Resume / suspend must appear in pairs. Otherwise, it is very prone to deadlock, because the suspend method does not release the lock. If the target thread using suspend holds a lock on an important system resource, no thread can use this resource until the target thread to suspend is resumed, If a thread attempts to hold this important system resource lock before resuming the target thread and then resuming the target thread, the two threads will deadlock with each other and freeze the thread.

In the relatively stable JDK 1.0 In version 2, you can find classes such as thread and threadusage, which are also the two core classes in the thread model. The entire version contains only a few packages: Java io、 java. util、java. NET、java. AWT and Java Applet, so this very original version of Java established a persistent threading model from the beginning.

JDK 1.2

Jdk1 at the end of 1998 Version 2 officially divides Java into three different directions: J2EE / J2SE / J2ME. In this version, Java tries to use swing to correct errors made in AWT, such as using too much synchronization. Unfortunately, Java itself determines that the performance and response of AWT or swing are not satisfactory, which is also a reason why java desktop applications are difficult to compare with their server-side applications. In the later SWT of IBM, JDK seems to reflect on itself and stop after JDK 1.2. It is worth noting that the following principles are usually followed when repairing low version problems with high version JDK:

Downward compatibility. Therefore, you can often see many newly redesigned packages and classes, as well as deprecated classes and methods, but they cannot be easily deleted. Strictly follow the JLS (Java language specification) and put the new JSR passed (Java specification request) is added to JLS, so the document itself is also downward compatible. Later versions can only further explain and enhance features, and there will be nothing to do with some designs with poor scalability at first. This can also be seen in the introduction to reentrantlock below. In this version, the following three methods are officially abolished: sto P (), suspend (), and resume (). In this JDK version, the thread variable ThreadLocal is introduced:

JDK 1.4

Jdk1.0 released in April 2002 4, NiO was officially introduced. JDK provides a group of multiplexing IO solutions based on the original standard IO.

By attaching multiple channels to a selector and detecting through unified polling threads, whenever data arrives, the monitoring event is triggered and the event is distributed, instead of making each channel consume for a long time and blocking a thread waiting for the data flow to arrive. Therefore, the obvious advantages of NiO can only be seen in the high concurrency scenario with fierce competition for resources.

Compared with the traditional flow oriented method, this block oriented access method will lose some simplicity and flexibility.

JDK 5.0

JDK 1.5 has been released since September 2004 and officially changed its name to 5.0. There is a joke that there is a saying in the software industry called "don't use software with version less than 3.0", which means that if the version is too small, the software quality is often poor - but according to this saying, when will the original version naming method of JDK have 3.0, so it will be directly upgraded to 5.0 after 1.4 through the change of version naming method.

Executors are used to create various thread pools. Thread pools such as newfixedthreadpool, newcachedthreadpool, newsinglethreadexecution scheduledexecutorservice are used to optimize the performance of threads

Callable and Futrue executorservice can also call the submit (callable) method to execute a task. Define the task content in the call () method and return a value. The submit method will return a future object. At the end of task execution, the get () method of the future object can get the value returned by the call () method. If the task is not completed when the get () method is called, Then the thread will block the waiting task to complete the Futrue implementation principle, which is similar to the callback function submit of Java. It will return directly to future object. In the background new, a new thread will access data, and then the function will be returned after obtaining the data.

Semaphore can specify the number of threads executing simultaneously when multiple threads are concurrent. Use the constructor semaphore (int) to create semaphores and specify the number of concurrent semaphores. After the thread starts executing, calling the acquire () method takes up a concurrency number. When the thread ends, it uses release () to release a concurrency number.

Exchange can set wait when multithreading is concurrent, wait for another thread to run to a specified location, and exchange data. Use the constructor exchange() to create an object. After the thread starts, you can use the exchange (object) method to control the current thread waiting until another thread also calls the method to exchange data and continue execution.

Reentrantlock reentrantreadwritelock implementation the lock interface can autonomously implement finer operations on locks (it is not recommended in the Java programming idea, unless concurrent programming is particularly powerful, because there may be unexpected problems in autonomous concurrency control. Generally, the synchronized keyword is recommended. The gradual optimization function of synchronized in each version is similar to lock, and there will be optimization in the later stage.)

The newcondition() method of condition lock can obtain a condition. The condition object has the functions of wait(), notify(), and notifyall() similar to the object. They are await(), signal(), and signalall() respectively. The difference is that if synchronized is used, only the lock object can be used to wait(), notify(), and notifyall(), At this time, the notify () method can only wake up a random thread. When using condition, you can create multiple branch objects, let the thread wait on different branches, and wake up the thread on the specified branch

JDK 5.0 is not just a change in the naming method of version numbers. For multi-threaded programming, two major events have taken place here, the official release of JSR 133 and JSR 166.

JSR 133

JSR 133 redefines the JAVA memory model. In fact, before that, common memory models include continuous consistent memory model and antecedent occurrence model.

For the continuous consistency model, the order of program execution is completely consistent with the order displayed on the code. This is difficult to guarantee for modern multi-core CPU with optimized instruction execution. Moreover, the guarantee of sequence consistency severely limits the runtime optimization of the code by the JVM.

However, the happens before specified by JSR 133 makes the order of executing instructions flexible:

In the same thread, According to the order of code execution (that is, the order of code semantics), the previous operation precedes the next operation. The unlocking operation of a monitor object precedes the subsequent locking operation of the same monitor object. The writing operation of the volatile field precedes the subsequent reading operation of the field and the start operation of the thread (calling the start() of the thread object) Method) before any other operation of this thread, all operations in a thread call the join () method on this thread. If operation a takes precedence over B and operation B takes precedence over C, operation a takes precedence over C and in memory allocation, Separate the working memory (even including) of each thread from the main memory, which gives the JVM a lot of space to optimize the execution of instructions in the thread. Variables in the main memory can be copied to the working memory of the thread for separate execution. After execution, the results can be brushed back to the main memory at a certain time:

However, how to ensure data consistency among threads? The method given by JLS is that by default, data consistency at any time cannot be guaranteed, but data consistency can be achieved through the use of synchronized, volatile and final keywords with enhanced semantics.

JSR 166

The contribution of JSR 166 is the introduction of Java util. Concurrent this package. Atomicxxx, an atomic type, was explained earlier, The internal implementation ensures its atomicity through a compareandset (x, y) method (CAS), and this method traces to the bottom layer through a separate instruction of the CPU. What this method does is to ensure that when a variable takes x, the value x is replaced by Y. in this process, there is no locking behavior, so its performance is generally higher than that of synchronized.

Using the copy of immutable objects (such as copyonwrite) can also achieve concurrent access without lock. For example, there is a linked list in which each node contains two values. Now I want to replace the middle node (2,3) with (4,5). If synchronization is not used, I can do this:

Build a new node and connect it to node (4,6), and then replace the pointer points from (1,1) to (2,3) with the pointer points from (1,1) to (4,5).

In addition to the two, there are many ways to implement atomic operations without synchronization, such as the Peterson algorithm I introduced.

The following table shows the common containers involved in JDK 5.0:

Of which:

The containers in the unsafe column are all pre JDK versions and are non thread safe; The containers in the synchronized column are available in the version before JDK, and thread safety is guaranteed through the synchronized keyword synchronization method; The containers in the concurrent PKG column are all newly added containers, which are thread safe, but they do not use synchronization to achieve thread safety. Let's talk about thread pool support. Before talking about thread pool, we have to clarify the concept of future. Future is also a new class in JDK 5.0. It is a result object used to integrate synchronous and asynchronous. The execution of an asynchronous task is returned immediately through the future object. If you want to obtain the result synchronously, you only need to call its get method and will not return it to you until the result is obtained. Otherwise, the thread will always hang there. Future can be seen as a partial repair made by JDK for its threading model. In the past, when programmers considered multithreading, they could not complete it with object-oriented thinking, and had to consider many thread oriented behaviors. However, future and barrier and other classes to be mentioned later can make it possible to, Programmers can get rid of heavy thread thinking. Decouple the thread control part from the business logic part.

JDK 6.0

JDK 6.0 makes some optimizations for locks, such as lock spin, lock elimination, lock merging, lightweight locks, biased locks, etc.

Cyclicbarrier is a newly added class for process control in JDK 6.0. This class can ensure that multiple tasks can be executed in parallel, and then perform the next operation uniformly:

Another similar class is countdownlatch (using countdown counting). The emergence of such a class marks that JDK's concurrent design has gradually changed from micro to macro, and began to pay more attention to concurrent program flow and even framework design. We will continue to see such ideas in JDK 7.0 below.

The difference between the two is that cyclicbarrier controls multiple threads, that is, after multiple tasks are completed, multiple threads uniformly perform the next operation. Countdownlatch is for a single thread, that is, after multiple threads are completed, one thread performs the next operation.

JDK 7.0

JDK 7.0 in 2011 further improved the function of concurrent process control, such as fork join framework:

Decompose the task into different sub tasks to complete; For example, phase integrates the functions of cyclicbarrier and countdownlatch, but provides the ability to dynamically modify dependent targets; There are also the new open features of nio2. I won't introduce it in detail here.

JDK 8.0

Longadder is used in a similar way to atomiclong, but its performance is better than atomiclong.

Both longadder and atomiclong use atomic operations to improve performance. However, longadder performs hot spot separation on the basis of atomiclong. Hot spot separation is similar to reducing lock granularity in lock operation. It separates a lock into several locks to improve performance. In lock free, a similar method can be used to increase the success rate of CAS and improve performance.

Completabilefuture implements the completionstage interface (more than 40 methods), most of which are used in functional programming, and supports streaming calls

Completable future is an enhanced version of future in Java 8

Stampedlock is an improvement of readwritelock. The difference between stampedlock and readwritelock is that stampedlock believes that reading should not block writing. Stampedlock believes that when reading and writing are mutually exclusive, reading should be reread instead of not allowing the writing thread to write. This design solves the problem of writing thread starvation when using readwritelock when reading more and writing less.

Therefore, stampedlock is an improvement in favor of writing threads.

JDK 9.0

Oracle announced that Java 9, originally scheduled to be launched in March 2017, will be released in July 2017, mainly because jigsaw, the built-in modular architecture of Java 9, takes longer to develop.

Improve lock contention mechanism

Lock contention limits the performance of many Java multithreaded applications. The new lock contention mechanism improves the performance of Java object monitor, It has been verified by a variety of benchmarks (such as volano), which can estimate the maximum throughput of the JVM. In fact, the new lock contention mechanism has achieved excellent results in 22 different benchmarks. If the new mechanism can be applied in Java 9, the performance of the application will be greatly improved. For more information, see jep143.

Reference blog: http://blog.csdn.net/findmyself_for_world/article/details/41981355

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>