Thinking in Java from Chapter 21

Source: Internet
Author: User
Tags terminates

From thinking in Java 4th Edition

Concurrent

A thread can drive a task, so you need a way to describe the task , which can be provided by the Runnable interface.

To define a task, you only need to implement the Runnable interface and write the run () method so that the task can execute your command.

public class LiftOff implements Runnable {protected int countdown = 10;//defaultprivate static int taskcount = 0;private Final int id = taskcount++;p ublic LiftOff () {}public LiftOff (int countdown) {this.countdown = countdown;} Public String status () {return "#" + ID + "(" + (Countdown > 0? Countdown: "liftoff!") + "). ";} public void Run () {while (countdown--> 0) {System.out.println (status)); Thread.yield ();}}}

When you export a class from runnable, it must have the run () method, but it does not produce any intrinsic threading capability. To implement threading behavior, you must explicitly attach a task to the thread.

The traditional way to turn a Runnable object into a work task is to submit it to a thread constructor:

public class Basicthread {public static void main (string[] args) {thread t = new Thread (new LiftOff ()); T.start (); System.out.println ("Waiting for LiftOff");}} /* output:waiting for Liftoff#0 (9), #0 (8), #0 (7), #0 (6), #0 (5), #0 (4), #0 (3), #0 (2), #0 (1), #0 (liftoff!), */

The thread constructor requires only one Runnable object.

1. Call the start () method of the thread object to perform the necessary initialization operations for the thread.

2. Call the Run () method of the Runnable object to start the task in this new thread.

You can see from the output that the start () method returns quickly because the "waiting for LiftOff" message appears before the countdown is complete.

You actually produce a call to the Liftoff.run () method, and this method is not yet complete, but because Liftoff.run () is executed by a different thread, you can still perform other operations in the main () thread.

If you add more threads to drive more tasks, you can see how all tasks interact with each other:

public class Morebasicthreads {public static void main (string[] args) {for (int i = 0; i < 5; ++i) New Thread (New LiftOff ( ). Start (); System.out.println ("Waiting for LiftOff");}} /* output:waiting for Liftoff#3 (9), #1 (9), #3 (8), #1 (8), #3 (7), #1 (7), #1 (6), #1 (5), #1 (4), #1 (3), #1 (2), #1 (1), #1 (liftof f!), #4 (9), #4 (8), #4 (7), #4 (6), #2 (9), #2 (8), #2 (7), #2 (6), #2 (5), #2 (4), #2 (3), #2 (2), #2 (1), #2 (liftoff!), #0 (9), #4 (5) , #3 (6), #4 (4), #3 (5), #4 (3), #3 (4), #4 (2), #3 (3), #4 (1), #3 (2), #4 (liftoff!), #0 (8), #3 (1), #0 (7), #3 (liftoff!), #0 (6), # 0 (5), #0 (4), #0 (3), #0 (2), #0 (1), #0 (liftoff!), * *

Using executor

Executor provides an indirect layer between the client and the task execution , and the Mediation object performs the task, unlike the client's direct execution of the task.

Executor is used to explicitly create a thread object in place of Morebasicthreads.java.

Executorservice knows how to build the context to execute the Runnable object.

Import java.util.concurrent.*;p Ublic class Cachedthreadpool {public static void main (string[] args) {Executorservice exec = Executors.newcachedthreadpool ();   No space between New and cachedfor (int i = 0; i < 5; ++i) Exec.execute (New LiftOff ()); Exec.shutdown ();}} /* Output: #0 (9), #2 (9), #0 (8), #1 (9), #0 (7), #0 (6), #0 (5), #0 (4), #0 (3), #0 (2), #0 (1), #0 (liftoff!), #2 (8), #1 (8), #3 (9), #2 (7), #1 (7), #3 (8), #2 (6), #1 (6), #3 (7), #2 (5), #2 (4), #4 (9), #3 (6), #1 (5), #3 (5), #1 (4), #1 (3), #1 (2), #1 (1), #1 (LiftOff !), #4 (8), #2 (3), #4 (7), #4 (6), #3 (4), #4 (5), #3 (3), #4 (4), #3 (2), #4 (3), #3 (1), #4 (2), #2 (2), #4 (1), #4 (liftoff!), #3 (Lif toff!), #2 (1), #2 (liftoff!), */

In the example above, Cachedthreadpool will create a thread for each task.

The Executorservice object is created using the static Executor method, which determines its executor type.

The common scenario is that executor is used to create and manage all the tasks in the system.

A call to the shutdown () method prevents the new task from being submitted to this executor, and the current task (the thread in this case, main) will continue to run all tasks that were committed before shutdown () was invoked.

The following program shows that Cachedthreadpool is replaced with a different type of executor. Fixedthreadpool uses a limited set of threads to perform the submitted tasks

Import java.util.concurrent.*;p Ublic class Fixedthreadpool {public static void main (string[] args) {//Constructor argument is number of threads:executorservice exec = Executors.newfixedthreadpool (5), for (int i = 0; i < 5; ++i) Exec.exe Cute (new LiftOff ()); Exec.shutdown ();}} /* Output: #0 (9), #2 (9), #4 (9), #0 (8), #2 (8), #3 (9), #1 (9), #1 (8), #0 (7), #4 (8), #0 (6), #4 (7), #0 (5), #4 (6), #4 (5), #4 (4), #4 (3), #4 (2), #4 (1), #4 (liftoff!), #1 (7), #1 (6), #1 (5), #1 (4), #1 (3), #1 (2), #1 (1), #1 (liftoff!), #3 (8), #2 (7), #0 (4), #3 (  7), #2 (6), #0 (3), #3 (6), #2 (5), #0 (2), #3 (5), #0 (1), #3 (4), #2 (4), #0 (liftoff!), #3 (3), #2 (3), #3 (2), #2 (2), #3 (1), #2 (1), #3 (liftoff!), #2 (liftoff!), */

With Fixedthreadpool, you can pre-execute expensive thread allocations at once. This saves time because you do not have to pay for each task to create the thread overhead.

Singlethreadexecutor is like a fixedthreadpool with a number of threads of 1. If multiple tasks are submitted to Singlethreadexecutor, the tasks are queued, each task ends before the next task starts, and all tasks use the same thread.

In the following example, you can see that each task is done in the order in which they were submitted, and before the next task begins. So singlethreadexecutor serializes all the tasks submitted to them and maintains its own (hidden) hanging task.

Import java.util.concurrent.*;p Ublic class Singlethreadexecutor {public static void main (string[] args) { Executorservice exec = Executors.newsinglethreadexecutor (); for (int i = 0; i < 5; ++i) Exec.execute (New LiftOff ()); exec. Shutdown ();}} /* Output: #0 (9), #0 (8), #0 (7), #0 (6), #0 (5), #0 (4), #0 (3), #0 (2), #0 (1), #0 (liftoff!), #1 (9), #1 (8), #1 (7), #1 (6), #1 (5), The #1 (4), #1 (3), #1 (2), #1 (1), #1 (liftoff!), #2 (9), #2 (8), #2 (7), #2 (6), #2 (5), #2 (4), #2 (3), #2 (2), #2 (1), #2 (liftoff!), #3 (  9), #3 (8), #3 (7), #3 (6), #3 (5), #3 (4), #3 (3), #3 (2), #3 (1), #3 (liftoff!), #4 (9), #4 (8), #4 (7), #4 (6), #4 (5), #4 (4), #4 (3), #4 (2), #4 (1), #4 (liftoff!), */

Return a value from a task

Runnable is a standalone task that performs work, but it does not return any values. If you want to be able to return a value, you must implement the callable interface instead of the Runnable interface.

Callable is a generic with a type parameter, whose type parameter represents the value returned from the method call () and must be called using the Executorservice.submit () method:

Import Java.util.concurrent.*;import Java.util.*;class Taskwithresult implements callable<string> {private int Id;public taskwithresult (int id) {this.id = ID;} Public String Call () {return ' result of Taskwithresult ' + ID;}} public class Callabledemo {public static void main (string[] args) {Executorservice exec = Executors.newcachedthreadpool () ; arraylist<future<string>> results = new arraylist<future<string>> (); for (int i = 0; i <; ++i ) Results.add (Exec.submit (New Taskwithresult (i))); for (future<string> Fs:results) try {//get () blocks until Completion:System.out.println (Fs.get ());} catch (Interruptedexception e) {System.out.println (e); return;} catch (Executionexception e) {System.out.println (e);} finally {Exec.shutdown ();}}} /* Output:result of Taskwithresult 0result of Taskwithresult 1result of Taskwithresult 2result of Taskwithresult 3result o F Taskwithresult 4result of Taskwithresult 5result of Taskwithresult 6result of Taskwithresult 7result of TasKwithresult 8result of Taskwithresult 9*/ 

The submit () method produces a future object that is parameterized with a specific type of callable return result.

1. You can use the Isdone () method to see if the future is complete

2. When the task is complete, you can call the Get () method to get the result

You can also call get () directly without Isdone (), in which case the get () will block until the result is ready.

Dormancy

An easy way to affect the behavior of a task is to call Sleep (), which causes the task to abort execution for a given time.

In the liftoff class, replacing the call of yield () with sleep () will get:

import java.util.concurrent.*;p ublic class Sleepingtask extends LiftOff {public void run () {try {while (countdown--> 0) {System.out.print (status ());//old-style//Thread.Sleep (+);//Java se5/6- Style:TimeUnit.MILLISECONDS.sleep (100);}} catch (Interruptedexception e) {System.err.println ("interrupted");}} public static void Main (string[] args) {Executorservice exec = Executors.newcachedthreadpool (), for (int i = 0; i < 5; ++i ) Exec.execute (New Sleepingtask ()); Exec.shutdown ();}} /* Output: #0 (9), #3 (9), #1 (9), #4 (9), #2 (9), #0 (8), #3 (8), #1 (8), #2 (8), #4 (8), #0 (7), #4 (7), #2 (7), #3 (7), #1 (7), #4 (6), #0 (6), #3 (6), #1 (6), #2 (6), #4 (5), #3 (5), #2 (5), #0 (5), #1 (5), #4 (4), #3 (4), #2 (4), #1 (4), #0 (4), #4 (3), #2 (3), #3 (3), #0 ( 3), #1 (3), #4 (2), #2 (2), #0 (2), #3 (2), #1 (2), #4 (1), #2 (1), #0 (1), #3 (1), #1 (1), #4 (liftoff!), #2 (liftoff!), #0 (liftoff!) , #3 (liftoff!), #1 (liftoff!), */

The sleep () call can throw a Interruptedexception exception and you can see that it is captured in run (). Because an exception cannot propagate back to main () across threads, you must locally handle all exceptions that are generated within the task.

Priority level

The scheduler will tend to have the highest priority thread execute first, however, this does not mean that a lower priority thread will not be executed (that is, priority does not cause deadlocks). A thread with a lower priority is simply a low-frequency execution.

Most of the time, all threads should run as the default priority. Attempting to manipulate the priority of a thread is usually an error.

You can use GetPriority () to read the priority of an existing thread, and you can modify it at any time by setpriority ():

Import java.util.concurrent.*;p Ublic class Simplepriorities implements Runnable {private int countdown = 5;private Volati Le double d;//No optimizationprivate int priority;public simplepriorities (int priority) {this.priority = priority;} Public String toString () {return thread.currentthread () + ":" + Countdown;} public void Run () {Thread.CurrentThread (). SetPriority (priority); and while (true) {//an expensive, interruptable operation: for (int i = 1; i < 100000; ++i) {D + = (Math.PI + MATH.E)/(double) i;if (0 = = i%) Thread.yield ();} System.out.println (this); if (0 = =--countdown) return;}} public static void Main (string[] args) {Executorservice exec = Executors.newcachedthreadpool (), for (int i = 0; i < 5; ++i ) Exec.execute (New Simplepriorities (thread.min_priority)); Exec.execute (new Simplepriorities (Thread.MAX_PRIORITY)) ; Exec.shutdown ();}}

Concessions

If you know that you have completed the work required during an iteration of the run () method's loop, you can give the thread scheduling mechanism a hint: your work is almost done, allowing other threads to use the CPU. This hint will be made through the yield () method (though it is only a hint that there is no mechanism to ensure that it will be adopted).

When yield () is called, you are also recommending that other threads with the same priority be able to run.

Background thread

A background (daemon) thread, which is a thread that provides a generic service in the background while the program is running, and that thread is not part of the program that is indispensable.

When all non-background threads end, the program terminates and kills all background threads in the process.

In turn, the program does not terminate as long as a non-background thread is running:

Import java.util.concurrent.*;import static net.mindview.util.print.*;p Ublic class Simpledaemons implements Runnable { public void Run () {try {if (true) {TimeUnit.MILLISECONDS.sleep ();p rint (Thread.CurrentThread () + "" + This);}} catch (Interruptedexception e) {print ("sleep () Interrupted");}} public static void Main (string[] args) throws Exception {for (int i = 0; i < ++i) {thread daemon = new Thread (new Sim Pledaemons ());d Aemon.setdaemon (TRUE);//Must call before Start () Daemon.start ();} Print ("All daemons started"); TimeUnit.MILLISECONDS.sleep (175);}} /* Output:all daemons startedthread[thread-4,5,main] [Email protected]thread[thread-2,5,main] [email  Protected]thread[thread-3,5,main] [Email protected]thread[thread-8,5,main] [email protected]Thread[ Thread-0,5,main] [Email protected]thread[thread-1,5,main] [Email protected]thread[thread-9,5,main] [ Email protected]thread[thread-7,5,main] [Email protected]thread[thread-5,5,main] [email proteCted]thread[thread-6,5,main] [email protected]*/ 

Simpledaemons.java creates the displayed threads so that they can be set to the background flag. By writing custom threadfactory, you can customize the properties (background, priority, name) of threads created by executor:

Package Net.mindview.util;import java.util.concurrent.*;p ublic class Daemonthreadfactory implements Threadfactory { Public Thread Newthread (Runnable r) {Thread t = new Thread (r); T.setdaemon (true); return t;}}

You can now pass a new daemonthreadfactory as a parameter to Executor.newcachedthreadpool ():

Package Net.mindview.util;import java.util.concurrent.*;p ublic class Daemonthreadfactory implements Threadfactory { Public Thread Newthread (Runnable r) {Thread t = new Thread (r); T.setdaemon (true); return t;}} Using a Thread Factory to create Daemons.import java.util.concurrent.*;import net.mindview.util.*;import static NET.MI ndview.util.print.*;p Ublic class Daemonfromfactory implements Runnable {public void run () {try {while (true) { TimeUnit.MILLISECONDS.sleep (+);p rint (Thread.CurrentThread () + "" + This);}} catch (Interruptedexception e) {print ("interrupted");}} public static void Main (string[] args) throws Exception {Executorservice exec = Executor.newcachedthreadpool (new Daemonth Readfactory ()); for (int i = 0; i <, ++i) Exec.execute (New Daemonfromfactory ());p rint ("All daemons started"); TimeUnit.MILLISECONDS.sleep (+);//Run for a while}}//Outputall daemons Startedthread[thread-0,5,main] [email  Protected]thread[thread-9,5,main] [email protected]thread[thread-7,5,main] [emAil protected]thread[thread-5,5,main] [Email protected]thread[thread-3,5,main] [email protected] Thread[thread-1,5,main] [Email protected]thread[thread-8,5,main] [email protected]thread[thread-2,5, Main] [Email protected]thread[thread-4,5,main] [Email protected]thread[thread-6,5,main] [email  Protected]thread[thread-0,5,main] [Email protected]thread[thread-9,5,main] [email protected]....*/

Each static Executorservice creation method is overloaded to accept a Threadfactory object, and this object is used to create a new thread:

Package Net.mindview.util;import java.util.concurrent.*;p ublic class Daemonthreadpoolexecutor extends Threadpoolexecutor {public daemonthreadpoolexecutor () {super (0, Integer.max_value, 60L, Timeunit, SECONDS, new Synchronousqueue<runnable> (), New Daemonthradfactory ());}}

You can use the Idaemon () method to determine whether a thread is a background thread. If it is a background thread, any thread it creates will automatically be set as a background thread.

Daemon threads Spawn Other Daemon threads.import java.util.concurrent.*;import static net.mindview.util.print.*; Class Daemon implements Runnable {private thread[] t = new thread[10];p ublic void Run () {for (int i = 0; i < t.length; + +i) {T[i] = new Thread (new Daemonspawn ()), T[i].start ();p RINTNB ("daemonspawn" + i + "started,");} for (int i = 0; i < t.length; ++i) PRINTNB ("t[" + i + "].isdaemon () =" + T[i].isdaemon () + ",") and while (true) Thread.yield ();}} Class Daemonspawn implements Runnable {public void run () {while (true) Thread.yield ();}} public class Daemons {public static void main (string[] args) throws Exception {thread d = new Thread (new Daemon ());d. Setda Emon (True);d. Start ();p RINTNB ("d.isdaemon () =" + D.isdaemon () + ",");/allow the daemon threads to//finish their start Up Processes:TimeUnit.SECONDS.sleep (1);}}  /* Output:d.isdaemon () = True, Daemonspawn 0 started, Daemonspawn 1 started, Daemonspawn 2 started, Daemonspawn 3 started, Daemonspawn 4 started, Daemonspawn 5 started, Daemonspawn 6 started, Daemonspawn 7 started, Daemonspawn 8 started, Daemonspawn 9 started, T[0].isdaemon () = True, t[1] . Isdaemon () = True, T[2].isdaemon () = True, T[3].isdaemon () = True, T[4].isdaemon () = True, T[5].isdaemon () = True, t[6].i Sdaemon () = True, T[7].isdaemon () = True, T[8].isdaemon () = True, T[9].isdaemon () = true,*/

You should be aware that a background process terminates its run () method without executing the FINALLY clause:

Daemon threads don ' t run the finally clauseimport java.util.concurrent.*;import static net.mindview.util.print.*; Class Adaemon implements Runnable {public void run () {try {print ("starting Adaemon"); TimeUnit.SECONDS.sleep (1);} catch (Interruptedexception e) {print ("Exiting via Interruptedexception");} finally {print ("This should always run?");}}} public class Daemonsdontrunfinally {public static void main (string[] args) throws Exception {thread t = new Thread (New ADa Emon ()); T.setdaemon (true); T.start ();}} /* Output:starting adaemon*/

In the current example, Runnable is implemented. In very simple cases, you might want to use this replaceable way of inheriting directly from thread:

public class Simplethread extends Thread {private int countdown = 5;private static int threadcount = 0;public Simplethread () {//Store the thread Name:super (integer.tostring (++threadcount)); start ();} Public String toString () {return "#" + getName () + "(" + Countdown + "),";} public void Run () {while (true) {System.out.print (this); if (0 = =--countdown) return;}} public static void Main (string[] args) {for (int i = 0; i < 5; ++i) new Simplethread ();}} /* Output: #2 (5), #2 (4), #2 (3), #2 (2), #2 (1), #4 (5), #4 (4), #4 (3), #4 (2), #4 (1), #5 (5), #5 (4), #5 (3), #5 (2), #5 (1), #3 (5), #3 (4), #3 (3), #3 (2), #3 (1), #1 (5), #1 (4), #1 (3), #1 (2), #1 (1), * *

You can assign a specific name to the thread object through the appropriate thread constructor, which can be obtained from ToString () by using GetName ().

Another idiom that you might see is self-administered runnable:

A Runnable containing its own driver Thread.public class Selfmanaged implements Runnable {private int countdown = 5;PRI Vate thread t = new Thread (this);p ublic selfmanaged () {T.start ();} Public String toString () {return Thread.CurrentThread (). GetName () + "(" + Countdown + "),";} public void Run () {while (true) {System.out.print (this); if (0 = =--countdown) return;}} public static void Main (string[] args) {for (int i = 0; i < 5; ++i) new selfmanaged ();}} /* OUTPUT:THREAD-3 (5), Thread-3 (4), Thread-3 (3), Thread-3 (2), Thread-3 (1), Thread-5 (5), Thread-5 (4), Thread-5 (3), Thread-5 (2), Thread-5 (1), Thread-6 (5), Thread-6 (4), Thread-6 (3), Thread-6 (2), Thread-6 (1), Thread-4 (5), Thread-4 (4), Thread-4 (3), Thread-4 (2), Thread-4 (1), Thread-7 (5), Thread-7 (4), Thread-7 (3), Thread-7 (2), Thread-7 (1), */

This has nothing to do with inheriting from thread, except that the syntax is slightly obscure. However, implementing an interface allows you to inherit another different class, and inheriting from thread will not work.

Note that the start () in this example is called in the constructor. You should be aware that starting a thread in the constructor can become problematic because another task may start executing before the end of the constructor, which means that the task has access to an object that is in an unstable state. This is another reason to preferably executor instead of explicitly creating a thread object.

Sometimes, it is useful to have thread code hidden in a class by using an inner class:

Thinking in Java from Chapter 21

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.