Scenario: The thread pool is often encountered during an interview and there are more scenes in the work, so it is necessary to figure it out.
1 Introduction
Java has joined the process of processing a batch of threads since 1.5, the executor in Java concurrency packages. This article mainly introduces the usage of Executorservice, the usage of runable and callable, and the usage of Executorcompletionservice .
The benefit of using executor to execute multiple threads is to avoid the overhead of thread creation and destruction to increase efficiency.
So if some scenarios require you to create threads repeatedly to handle similar transactions, consider using a thread pool to handle them.
In fact, executor itself does not realize the function of pure pool, but provides a way to obtain executorservice, and Executorservice is the real processing of thread pool related logic classes.
There are many ways to get executorservice under executor, such as a single thread pool, a thread pool of fixed threads, etc., but eventually the constructor of Executorservice is called to create, as follows:
Public Threadpoolexecutor (int corepoolsize,/ / Minimum number of threads int maximumpoolsize,// Maximum number of threads long KeepAliveTime,// line Cheng after which the wait time for subsequent threads timeunit Unit, // Unit of waiting time Blockingqueue<runnable> WorkQueue,// waiting thread queue threadfactory threadfactory)// Thread Production plant
1.1 runable
With this method, you can create a thread pool method that limits the number of threads and the wait time in the queue. Then, if you want to execute the thread through this thread pool:
Executorservice.execute (new Runnable () { @Override publicvoid Run () { System.out.println ("Execute in Pool:" + Thread.CurrentThread (). GetId ()); });
execution through the Execute () method is asynchronous, and it is not possible to know when the thread has finished executing .
If you want to know if the thread is finished, you can execute it in a different way (), then get to a future object and then use the Get () method to determine if the execution is complete:
future<?> future = Executorservice.submit (NewRunnable () {@Override Public voidrun () {Try{Thread.Sleep (3000); } Catch(interruptedexception e) {e.printstacktrace (); } System.out.println ("Execute in Pool:" +Thread.CurrentThread (). GetId ()); }});Try { if(Future.get () = =NULL) {System.out.println ("Finish!!!"); }} Catch(interruptedexception e) {e.printstacktrace ();}Catch(executionexception e) {e.printstacktrace ();}
But in this way only to know whether the thread is finished, but do not do the processing results of the various threads are returned to do the merge processing .
To accomplish this, you can use the callable interface to encapsulate the task logic, and the only difference between callable and runable is that it supports returning processing results:
1.2 Callable
you can handle the returned results after the thread has finished executing .
future<?> future = Executorservice.submit (new callable<string>() { @Override Public throws Exception { return "Hello callable!" ; }}); Try { catch (interruptedexception e) { catch ( Executionexception e) { e.printstacktrace ();}
The value returned in the call () method is the value of the future object get (). But what if there are multiple threads working on it and then merging the results of those threads?
Of course, you can use Executorservice to get the future object of each thread that is put into the threads pool, and then go through get () and then do the merge process. However, it is obvious that this method is not able to achieve the first to be merged first, but depends on the time of traversal , which obviously reduces the processing efficiency.
To handle this scenario, you can use a different service–executorcompletionservice:
1.3 Executorcompletionservice
Packagetest03;Importjava.util.concurrent.Callable;ImportJava.util.concurrent.CompletionService;Importjava.util.concurrent.ExecutionException;ImportJava.util.concurrent.ExecutorCompletionService;ImportJava.util.concurrent.ExecutorService;Importjava.util.concurrent.Executors;Importorg.junit.Test; Public classexecutorcompletionservicetest {@Test Public voidTest () {Executorservice Executorservice= Executors.newfixedthreadpool (4); Completionservice<Long> Completionservice =NewExecutorcompletionservice<long>(Executorservice); for(inti = 0; I < 4; i++) { LongSleep = (5-i) * 1000; Completionservice.submit (NewExeworker (sleep));//using Completionservice to invoke a thread, you can do it first. } for(inti=0;i<4;i++){ Try{System.out.println (Completionservice.take (). Get ()+ "get!");//Gets the result of a thread-processed return}Catch(interruptedexception e) {e.printstacktrace (); } Catch(executionexception e) {e.printstacktrace (); } } }}classExeworkerImplementsCallable<long> { Private Longsleep; PublicExeworker (Longsleep) { This. Sleep =sleep; } @Override PublicLong Call ()throwsException {System.out.println (Sleep+ "executing!"); Thread.Sleep (sleep); System.out.println (Sleep+ "done!"); returnsleep; }}
Take the thread's sleep time as the thread name, and then output the result as:
It can be seen that the place where the loop gets the results of the processing is done in a way that first returns first. one constraint to this approach is the need to know how many threads are being processed . (not very understanding)
In fact, the Completionservice bottom is a blockingqueue to store the processing results, you can also use its own packaged with a time-out poll method to get the results returned.
(go) Java Concurrency executor