& Lt; about the concurrency framework & gt; Java Native thread pool principle and supplement to Guava, javaguava

Source: Internet
Author: User

<About concurrency framework> Java Native thread pool principle and supplement with Guava, javaguava

For original blog reposted, contact the blogger!

 

 

I haven't updated my blog in just two months.

As a result, I feel that I have to learn too much. Instead of spending a few hours writing and sharing experiences, I 'd better read more technical books.

2. There are already many mature Chinese articles on the Internet to introduce these usage, and I will repeat them to repeat them.

Therefore, since we are planning to write data, we hope to have some distinctive usage and new ideas, which will inspire you.

 

  Using the Java medium-cost framework to help us develop concurrent applications can save time for building projects and improve application performance.

 

Java object instance locks have four statuses: no locks, biased locks, lightweight locks, and weight locks. Most concurrent applications that exit the framework need to manually release the lock. The most direct thing is to use the synchronized and volatile keywords to lock an object or code block to limit the number of visits each time, from the competition between objects, collaboration between objects can also be realized. However, manually implemented applications are not only time-consuming, but also performance needs to be improved. By the way, I wrote an article about a multi-thread download Tool Based on Qt and Linux. (I don't need to know more about this download tool here. Please continue to read it ), take the download tool as an example:

First, one of the most stupid problems with a download tool is to hand over the number of download threads to the user for configuration. For example, if a user thinks that the number of threads responsible for downloading is as high as possible, the user simply configures 50 threads to download a task, the download performance of this download tool is even inferior to that of a single process. The most direct reason is that the JVM spends a lot of computing resources on context switching between threads. For a concurrent application: For CPU-intensive tasks, A good number of threads is twice the actual number of CPU processors. For I/O-intensive tasks, A good number of threads is 1.5 to 2 times of the actual number of CPU processors (it is not clear where this sentence is, but it is still credible ). Improper Number of execution threads will cause potential risks such as thread jitter and CPU jitter. If re-development is required, I will use this thread pool method to use the Relationship Mode between producers and consumers to asynchronously process packets transmitted over HTTP.

Second, because it may take a long time to wait for the receipt of HTTP packets, the computing resources consumed by processing the packet parsing format and so on are quite small. Synchronous processing of these two things will inevitably result in the download process idling or blocking for a period of time, which is also very unreasonable. If re-development is required, it is necessary to decouple the receipt of HTTP packets and the resolution of HTTP packets. Although the thread pool can be used for processing, obviously, the performance improvement in this way is very small, so there is no need to implement it. A single thread can quickly complete packet parsing.

 

  Okay, back to the topic. In short, context switching between threads causes performance degradation. So how can we reduce context switching?

 

 

 

 

  1. Lock-free concurrent programming

    Multi-threaded competitive locks can cause context switching. Therefore, when processing data using multiple threads, you can use some methods to avoid using locks. For example, you can use the Hash algorithm to modulo data IDs, different threads process data in different segments.

  2. CAS Algorithm

    Java's Atomic package uses the CAS algorithm to update data without locking (but there is still a idling thread ).

  3. Use the least thread

    Avoid creating unnecessary threads, such as few tasks, but creating multiple threads for processing. This will cause a large number of threads to wait.

  4. coroutine

    Multi-task scheduling is implemented in a single thread, and switching between multiple tasks is maintained in a single thread.

 

 

 

  In general, using the Java thread pool brings the following three benefits:

 

1. reduce resource consumption: Reuse created threads to reduce the consumption caused by thread creation and destruction.

2. Improve the response speed: when the task arrives, the task can be executed immediately without waiting for the thread to be created.

3. Improve the manageability of threads: threads are scarce resources, if they are not created. It not only reduces the system stability, but can be uniformly allocated, optimized, and monitored using the thread pool. However, it is necessary to make rational use of the thread pool. The implementation principles must be well known.

 

Shows the implementation principle of the thread pool:

Two-Level Scheduling Model of the Executor framework:

 

In the HotSpot VM thread model, Java threads are mapped to local operating system threads one by one. A local operating system thread is created when the Java thread starts. When the Java thread ends, the operating system will also be recycled. The operating system schedules and assigns them to available CPUs.

At the upper layer, Java multi-threaded programs usually break down applications into several tasks, and then map these tasks to a fixed number of threads using the user-level scheduler (Executor framework). At the bottom layer, the operating system kernel maps these threads to the hardware processor. This two-level scheduling model is essentially a solution of work order elements and execution mechanisms.

 

Recursive Scheduling Model of Fork/Join framework:

 

To improve the execution efficiency of applications on multi-core processors, we can only improve the parallel capability of applications. The conventional approach is to use multithreading to allow more tasks to be processed at the same time, or to allow some operations to be executed asynchronously, this simple multi-thread processing method can effectively use processing resources when the number of processor cores is small, because when the number of processor cores is small, only a few tasks can be executed in parallel. However, when the number of processor cores grows to a large number and hundreds of thousands of cores, such concurrent processing methods based on tasks cannot fully utilize the processing resources, because the general application does not have so many concurrent processing tasks (the server program is an exception ). Therefore, you can only consider splitting a task into multiple units. Each unit must execute the final merge results for each unit. One way to split a task in parallel is to hope for a hardware platform or an operating system, but there is no good result in this field. Another solution is to only rely on the application itself to split and execute tasks.

At first glance, the Fork/Join model looks like a reference to MapReduce, but it is not sure what the reason is. The actual performance improvement is far inferior to that of Executor. Even when the recursive stack reaches more than 10 layers, the JVM will be stuck or crashed. From the perspective of the computer's physical principle, the actual performance of the Fork/Join framework is not as good as imagined, so I will only talk about it a little bit, and I will not go into it any more.

 

 

 

The Executor framework consists of tasks, task execution, and asynchronous computing results.

 

The main classes and interfaces are described as follows:

 

1. Executor is an interface that separates job submission from job execution.

2. ThreadPoolExecutor is the core of the thread pool and is used to execute submitted classes.

3. The Future interface and the FutureTask class implementing the Future interface represent the result of asynchronous calculation.

4. The implementation classes of the Runnable interface and Callable interface can be ThreadPoolExecutor or other executions.

 

Let's take a look at a direct example (implemented using SingleThreadExecutor. The specific principles are described below ):

 

1 public class ExecutorDemo {2 3 4 public static void main (String [] args) {5 6 // ExecutorService fixed = Executors. newFixedThreadPool (4); 7 ExecutorService single = Executors. newSingleThreadExecutor (); 8 // ExecutorService cached = Executors. newCachedThreadPool (); 9 // ExecutorService sched = Executors. newScheduledThreadPool (4); 11 12 Callable <String> callable = Executors. callable (new Runnable () {13 @ Override14 public void run () {15 for (int I = 0; I <100; I ++) {16 try {17 System. out. println (I); 18} catch (Throwable e) {19 e. printStackTrace (); 20} 21} 22} 23}, "success"); 24 // The figure here is clever, use the callable method of the Executors tool class to decorate an anonymous Runnable object as a Callable object as the parameter 25 ure <String> f = single. submit (callable); 26 try {27 System. out. println (f. get (); 28 single. shutdown (); 29} catch (Throwable e) {30 e. printStackTrace (); 31} 32} 33}

 

As shown in the Code, there are usually four Exector implementation classes to create Executor instances through the Executors factory method. The specific differences and features are as follows:

 

1. FixedThreadPool

 

This is my most commonly used implementation class. The most direct method in Java is to use executors allocated with the number of processors together with Runtime. getRuntime (). availableProcessors. The internal structure is roughly as follows:

The instance creation function is Executors. newFixedThreadPool (int nThread );

Java. util. in the source code of the concurrent package, the queue uses the new queue blockingqueue <Runnable>, which is an unbounded queue. That is to say, the task may have an infinite backlog in this waiting queue, there are some hidden risks in actual use. However, it is quite easy to construct. I personally suggest constantly querying size () during use to ensure that the blocked queue will not grow infinitely.

 

2. SingleThreadExecutor

It is equivalent to Executors. newFixedThreadPool (1.

 

3. CachedThreadPool

Unlike the previous two implementation classes, SynchronousQueue is used to replace javasblockingqueue. To put it simply, SynchronousQueue is a non-capacity queue, and an offer must correspond to a poll. Of course, the so-called poll operation is performed by the actual JVM worker thread, so for developers, this is a thread pool that will be blocked due to working thread saturation. (This is similar to java. util. concurrent. Exchanger, but Exchanger only applies to two JVM threads, and the blocking mechanism of SynchronousQueue is for multiple producers and consumers .)

 

4. ScheduledThreadPoolExecutor

This implementation class uses DelayQueue internally. DelayQueue is actually an encapsulation of a priority queue. Early tasks have a higher priority. It is mainly used to run tasks after a given delay, or regularly execute tasks. ScheduledThreadPoolExecutor features similar to Timer, but ScheduledThreadPoolExecutor is more flexible than Timer, and multiple background threads can be specified in the constructor.

 

 

Future interface and ListenableFurture Interface

 

The Future interface provides a stub (stub) for the asynchronous computing result retrieval. However, every time you call the get method of the Future interface to retrieve the computing result, you may need to block it. In this case, the consumption of asynchronous computing and synchronous computing is the same in the worst case. Therefore, the Guava Library provides a very powerful post-decoration Future interface. The observer mode is used to specify a Runnable object for the addListener execution immediately after the asynchronous computation is complete, from the implementation of "immediate notification of completion ". Here a valid Tutorial: http://ifeve.com/google-guava-listenablefuture/ is provided

 

 

 

 

 

  

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.