Java concurrent Programming 8_ thread pool usage

Source: Internet
Author: User

do not use a thread pool

1. Serial Execution of tasks

Class Singlethreadwebserver {public static void main (string[] args) {serversocket socket = new ServerSocket, while (Tru e) {Socket conn = socket.accept (); HandleRequest (conn);}}}

Waits for one connection processing to complete before processing the next user request, providing high throughput and fast response times with low CPU utilization.

2. Start a new thread for each request

Class Threadpertaskwebserver {public static void main (string[] args) {serversocket socket = new ServerSocket, while (tr UE) {FINAL Socket conn = socket.accept (); Runnable Runnable = new Runnable () {@Overridepublic void run () {handlerequest (conn);}}; New Thread (runnable). Start ();}}}

For each user request to open a new thread, the processing of the task is separated from the main thread, so that the task can be processed in parallel. Improves the performance and responsiveness of serial execution.

Insufficient:

The cost of the thread life cycle is very high. Threads are created and destroyed at a cost, and different platform overhead is different.

Resource consumption. Too many threads consume system resources, such as memory consumption for idle threads, and other performance overhead when a large number of threads compete for CPU.

Stability. The number of threads that can be created is limited.

Executor Frame

A task is a set of logical units of work, while a thread is the mechanism by which the task executes asynchronously. There are some strict restrictions in the previous two ways: The problem with serial execution is poor responsiveness and throughput, and the issue of "assigning a thread to each task" is the complexity of resource management.

The Java.util.concurrent package provides a flexible thread pool implementation as part of the executor framework

Public interface Executor {    void execute (Runnable command);}

Executor is a simple interface, but it provides the foundation for a flexible and powerful framework of asynchronous task execution that supports many different types of task execution strategies. It provides a standard way to decouple the commit and execution processes of a task and to represent tasks with runnable. The implementation of executor also provides support for the lifecycle, as well as mechanisms such as statistical information, application management mechanisms, and performance monitoring.

Thread pool-based Web server

public class Taskexecutionwebserver {    private static final int nthreads = +;    private static final Executor exec =             executors.newfixedthreadpool (nthreads);    public static void Main (string[] args) throws IOException {        ServerSocket server = new ServerSocket (n);        while (true) {            final Socket connection = Server.accept ();            Runnable task = new Runnable () {                @Override public                void Run () {                    handlerrequest (connection);                }            };            Exec.execute (Task);}}}    

Using the framework provided by executor, we can modify the Taskexecutionwebserver as a single-threaded (serial execution) behavior similar to Singlethreadwebserver.

public class Singlethreadexecutor implements executor{@Overridepublic void execute (Runnable command) {Command.run ();}}

Similarly, we can modify the behavior of Taskexecutionwebserver for multithreaded (starting a thread for each request) similar to Threadpertaskwebserver.

public class Threadpertaskexecutor implements executor{@Overridepublic void execute (Runnable command) {new Thread ( command). Start ();}}

Thread pool can be created through the static factory method in executor

Creates a fixed-length thread pool that creates a thread every time a task is committed, until the maximum number of thread pools is reached, and if an exception occurs on the thread, it is recreated

public static executorservicenewfixedthreadpool (int nthreads) {...}

Creates a single thread to perform the task, and creates a new thread if the thread has an exception. The pool can perform tasks in the queue sequentially (such as FIFO,LIFO, priority, etc.)

public static executorservicenewsinglethreadexecutor () {...}

There is no length limit for this thread pool, which is recycled when too many threads are created

public static Executorservicenewcachedthreadpool () {...}

Create a fixed-length thread pool and perform tasks in a deferred or timed manner

public static scheduledexecutorservicenewscheduledthreadpool{...}

Executor is the top-level interface

Executorservice inherits from executor, adding some methods for life cycle management and some methods of task submission.

Abstractexecutorservice implements the Executorservice interface, Threadpollexecutor inherits from Abstractexecutorservice.

Callable and future

The use of runnable has great limitations and cannot return a value or throw a checked exception. At this time callable can be competent. Using callable, you can return the results of the thread run, which is obtained through the Get method in Fuuture.

The future represents the life cycle of a task and provides a way to determine whether the task has been completed or canceled, and to get the results and cancel the task. The behavior of the Get method depends on the state of the task, and if the task has already completed, then get returns or throws exception immediately. If it is not completed, get will block until the task is completed. If the task throws an exception, then the get throws an exception.

Public interface Callable<v> {    V call () throws Exception;} Public interface Future<v> {    Boolean cancel (Boolean mayinterruptifrunning);    Boolean iscancelled ();    Boolean isDone ();    V get () throws Interruptedexception, Executionexception;    V get (long timeout, timeunit unit)        throws Interruptedexception, Executionexception, TimeoutException;}

There are several ways to create a future to describe a task. All the submit methods inside the Executorservice will return a future, so that a runnable or callable is submitted to executor and a future is used to get the task execution result or cancel the task.

Class Mycallable implements callable<string> {@Overridepublic String call () {try {TimeUnit.SECONDS.sleep (2);} catch (Interruptedexception e) {e.printstacktrace ();} return "Haha-callable";}} public class Testexecutor {public static void main (string[] args) {list<future<string> > futurelist = new Arra Ylist<future<string>> (); Executorservice exec = Executors.newcachedthreadpool (); for (int i = 0; i < 5; i++) {Futurelist.add (Exec.submit (New MyCa Llable ()));} for (future<string> future:futurelist) {try {System.out.println (Future.get ());} catch (Interruptedexception | Executionexception e) {e.printstacktrace ();}}}}

Output

Haha-callablehaha-callablehaha-callablehaha-callablehaha-callable

You can also explicitly instantiate a futuretask,futuretask for a specified runnable or callable and implement runnable, so it can be handed to thread or executor for execution.

Class Mycallable implements callable<string> {@Overridepublic String call () {try {random r = new Random (); TimeUnit.SECONDS.sleep (R.nextint (5));} catch (Interruptedexception e) {e.printstacktrace ();} return "Haha-callable";}} public class Testexecutor {public static void main (string[] args) {list<future<string> > futurelist = new Arra Ylist<future<string>> (); Executorservice exec = Executors.newcachedthreadpool (); for (int i = 0, i < 5; i++) {futuretask<string> future = n EW futuretask<string> (New Mycallable ()), Futurelist.add (future), New Thread (Future), start (); for (future<string> future:futurelist) {try {System.out.println (Future.get ());} catch (Interruptedexception | Executionexception e) {e.printstacktrace ();}}}}

As in the example above, a set of tasks are submitted to executor and you want the results to be obtained when the calculation is complete. You can keep the future associated with each task as described above, and then use the Get method in the for loop, and the problem is that the Get method blocks waiting for the result to be returned. Therefore, the results of the calculation are awaited in the order in which the tasks are added.

For example, if you add the task to the first task time 5s, the second 4s ... Fifth 1s, the output of these five tasks is not calculated as the first to get the value of the task performed first, because the Get method will block until the task is complete.

Class Mycallable implements callable<string> {private int id;public mycallable (int id) {this.id = ID;} @Overridepublic String Call () {try {TimeUnit.SECONDS.sleep (5-id)} catch (Interruptedexception e) {e.printstacktrace () ;} Return ID + "--haha-callable";}} public class Testexecutor {public static void main (string[] args) {list<future<string> > futurelist = new Arra Ylist<future<string>> (); Executorservice exec = Executors.newcachedthreadpool (); for (int i = 0; i < 5; i++) {Futurelist.add (Exec.submit (New MyCa Llable (i)));} for (future<string> future:futurelist) {try {System.out.println (Future.get ());} catch (Interruptedexception | Executionexception e) {e.printstacktrace ();}}}}

After 5S, it will print immediately, and it is not finished first.

0--Haha-callable1--haha-callable2--haha-callable3--haha-callable4--haha-callable

In fact, you can keep the future associated with each task as described above, and then use the Get method repeatedly in the For loop, setting timeout to 0, or judging the current task Isdone get, and polling to see if the task is complete. This method is sunran feasible but cumbersome.

Class Mycallable implements callable<string> {SimpleDateFormat df = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss"); private int id;public mycallable (int id) {this.id = ID;} @Overridepublic String Call () {try {TimeUnit.SECONDS.sleep (5-id)} catch (Interruptedexception e) {e.printstacktrace () ;} Return Df.format (New Date ()) + "" + ID + "--haha-callable";}} public class Testexecutor {public static void main (string[] args) {list<future<string> > futurelist = new Arra Ylist<future<string>> (); list<future<string> > finishedfuturelist = new arraylist<future<string>> (); Executorservice exec = Executors.newcachedthreadpool (); for (int i = 0; i < 5; i++) {Futurelist.add (Exec.submit (New MyCa Llable (i)));} while (Finishedfuturelist.size () <5) {for (future<string> future:futurelist) {if ( Finishedfuturelist.contains (future)) Continue;try {if (Future.isdone ()) {System.out.println (future.get (0), Timeunit.seconds)); Finishedfuturelist.add (future);}} CaTCH (Interruptedexception | executionexception | TimeoutException e) {e.printstacktrace ();}}}}

Output every second, and tasks that are completed first print

2015-08-24 10:12:08 4--haha-callable2015-08-24 10:12:09 3--haha-callable2015-08-24 10:12:10 2--haha-callable2015-08- 10:12:11 1--haha-callable2015-08-24 10:12:12 0--haha-callable

By polling, you can get the results of a task that is completed first. But it's more troublesome. Another better way is to complete the service (Completetionservice)

Class Mycallable implements callable<string> {SimpleDateFormat df = new SimpleDateFormat ("Yyyy-mm-dd HH:mm:ss"); private int id;public mycallable (int id) {this.id = ID;} @Overridepublic String Call () {try {TimeUnit.SECONDS.sleep (5-id)} catch (Interruptedexception e) {e.printstacktrace () ;} Return Df.format (New Date ()) + "" + ID + "--haha-callable";}} public class Testexecutor {public static void main (string[] args) {Executorservice exec = Executors.newcachedthreadpool () ; completionservice<string> completionservice = new executorcompletionservice<string> (exec); for (int i = 0; i < 5; i++) {completionservice.submit (new mycallable (i));} for (int j = 0; J < 5; J + +) {try {future<string> f = Completi Onservice.take (); System.out.println (F.get ());} catch (Interruptedexception | Executionexception e) {e.printstacktrace ();}}}}
Output every second, and tasks that are completed first print

2015-08-24 10:29:53 4--haha-callable2015-08-24 10:29:54 3--haha-callable2015-08-24 10:29:55 2--haha-callable2015-08- 10:29:56 1--haha-callable2015-08-24 10:29:57 0--haha-callable

Completetionservice is encapsulated into the future by taking out the tasks that have been completed.

Java concurrent Programming 8_ thread pool usage

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.