Turn: multi-thread programming-Practice (by axman)

Source: Internet
Author: User
Tags thread stop
Document directory
  • [Use of virtual locks]
  • [A deep understanding of thread objects and threads, threads and runtime environments]
Multi-thread programming-Practice (1)

Before entering the Practice section, let's briefly introduce the general principles of multi-threaded programming.

  [Security]Is the primary principle of multi-threaded programming. If more than two threads access the same object, one thread will corrupt the data of the other thread, which violates the security principle, such a program cannot be used in practical applications.

Security assurance can be ensured by designing secure classes and manually controlling programmers. If multiple threads access the same object without compromising security, such classes are thread-safe classes. In Java, for example, the string class is designed as a thread-safe class. If it is not a thread-safe class, the programmer needs to manually control its security when accessing the instances of these classes.

  [Feasibility]Is another important principle of multi-threaded programming. If only security is achieved, the program cannot continue to run after a certain point or multiple threads have deadlocks, such a program cannot be used as a real multi-threaded program.

The security and feasibility are relatively conflicting. The higher the security, the lower the program's availability. Comprehensive balance is required.

  [High Performance]The purpose of Multithreading is to increase the program running performance. If a multi-thread completes the work, it is not as fast as that of a single thread. Do not use multiple threads.

High-performance programs have the following factors:

  Data throughputThe processing capability that can be completed within a certain period of time.

  Response Speed, From the time when the request is sent to the time when the response is received.

  Capacity, Refers to the number of processed elegant jobs at the same time.

Security and feasibility are necessary. If the two principles are not met, it cannot be called a real multi-threaded program. High performance is the purpose of multi-threaded programming. It can be said that it is a sufficient condition. Otherwise, why is multi-threaded programming used?

 

[Producer and consumer model]

First, enter the first section of the actual practice with a producer and consumer model.

Who is protected in the producer and consumer models?

Multi-threaded programming is protecting some objects. These objects are "tight resources" and must be used to the maximum extent. This is also the reason for adopting multithreading. In the producer-consumer model, we want to protect the "warehouse". In my example,

It is a table ).

The Mode in my example is completely the producer-consumer mode, but I changed the name. Chef-diners mode. There is only one table in the dining room and a maximum of 10 dishes can be placed. Now there are four chefs cooking, every time you make a good disk, you can put it on the table (the producer puts the product in the warehouse), while 6 diners keep eating (the Consumer consumes the product to illustrate the problem, their food intake is unlimited ).

In general, the cook made a dish in-MS, while the diners had to eat a dish in-MS. When there are ten dishes on the table, no chefs can put them on the table. When there is no plate on the table, all diners have to wait.

We will design this program as follows:

Because we don't know what it is, we call it food:

 class Food{}

Then there is the table, because it needs to be put in order and retrieved in order (not two diners can win a third dish at the same time), so we expand the orders list, or you can use aggregation to set an aggregate list as an attribute for the same purpose. In this example, I use

Inheritance: input a maximum value that can be placed from the constructor.

class Table extends java.util.LinkedList{  int maxSize;  public Table(int maxSize){    this.maxSize = maxSize;  }}

Now we need to add two methods for it. One is how the cook puts food on it, and the other is how the diners take food from the table.

Food: Because a table is served by multiple chefs, the food to be served by the chefs should be synchronized, if there are already ten dishes on the table. All chefs have to wait:

 public synchronized void putFood(Food f){    while(this.size() >= this.maxSize){      try{        this.wait();      }catch(Exception e){}    }    this.add(f);    notifyAll();  }

Take food: Same as above. If there is no dish on the table, all diners will wait:

 public synchronized Food getFood(){    while(this.size() <= 0){      try{        this.wait();      }catch(Exception e){}    }    Food f = (Food)this.removeFirst();    notifyAll();    return f;  }

Chefs:

Since multiple chefs want to put food on one table, the tables they want to operate should be the same object, we passed in the table object from the constructor so that only one table is generated in the main thread.

When a cook is cooking for a certain period of time, I use sleep in the Make method to indicate that he will consume and use a random number of 200 plus 200 to ensure that the time is-MS. Put it on the table after you finish it.

There is a very important issue that must be noted here, that is, the scope of synchronization. Because the competition is a table, all putfood is synchronized, however, we cannot synchronize the time for the chefs to cook their own dishes, because they are made by themselves. Similarly, diners should not synchronize food, but compete only when taking food from the table. Therefore, the cook class code is as follows:

 class Chef extends Thread{  Table t;  Random r = new Random(12345);  public Chef(Table t){    this.t = t;  }  public void run(){    while(true){      Food f = make();      t.putFood(f);    }  }  private Food make(){    try{      Thread.sleep(200+r.nextInt(200));    }catch(Exception e){}    return new Food();  }}

Similarly, the Code for generating the diners class is as follows:

class Eater extends Thread{  Table t;  Random r = new Random(54321);  public Eater(Table t){    this.t = t;  }  public void run(){    while(true){      Food f = t.getFood();      eat(f);    }  }  private void eat(Food f){        try{      Thread.sleep(400+r.nextInt(200));    }catch(Exception e){}  }}

The complete program is here:

package debug;import java.util.regex.*;import java.util.*;class Food{}class Table extends LinkedList{  int maxSize;  public Table(int maxSize){    this.maxSize = maxSize;  }  public synchronized void putFood(Food f){    while(this.size() >= this.maxSize){      try{        this.wait();      }catch(Exception e){}    }    this.add(f);    notifyAll();  }    public synchronized Food getFood(){    while(this.size() <= 0){      try{        this.wait();      }catch(Exception e){}    }    Food f = (Food)this.removeFirst();    notifyAll();    return f;  }}class Chef extends Thread{  Table t;  String name;  Random r = new Random(12345);  public Chef(String name,Table t){    this.t = t;    this.name = name;  }  public void run(){    while(true){      Food f = make();      System.out.println(name+" put a Food:"+f);      t.putFood(f);    }  }  private Food make(){    try{      Thread.sleep(200+r.nextInt(200));    }catch(Exception e){}    return new Food();  }}class Eater extends Thread{  Table t;  String name;  Random r = new Random(54321);  public Eater(String name,Table t){    this.t = t;    this.name = name;  }  public void run(){    while(true){      Food f = t.getFood();      System.out.println(name+" get a Food:"+f);      eat(f);          }  }  private void eat(Food f){        try{      Thread.sleep(400+r.nextInt(200));    }catch(Exception e){}  }}public class Test {    public static void main(String[] args) throws Exception{      Table t = new Table(10);      new Chef("Chef1",t).start();      new Chef("Chef2",t).start();      new Chef("Chef3",t).start();      new Chef("Chef4",t).start();      new Eater("Eater1",t).start();      new Eater("Eater2",t).start();      new Eater("Eater3",t).start();      new Eater("Eater4",t).start();      new Eater("Eater5",t).start();      new Eater("Eater6",t).start();    }}

 

In this example, we mainly focus on the following aspects:

1. objects to be protected by the synchronization method. In this example, the table is protected. You cannot add or take dishes at the same time.

If we implement the putfood and getfood methods in the chefs and diners, we should do this:

(Take putfood as an example)

Class Chef extends thread {table t; string name; Public chef (string name, table t) {This. T = T; this. name = Name;} public void run () {While (true) {food F = make (); system. out. println (name + "put a food:" + F); putfood (f) ;}} Private food make () {random r = new random (200); try {thread. sleep (200 + R. nextint ();} catch (exception e) {} return new food ();} public void putfood (Food f) {// the method itself cannot be synchronized, because it synchronizes this. that is, the chef instance synchronized (t) {// The instance to be protected is t while (T. size ()> = T. maxsize) {try {T. wait () ;}catch (exception e) {}} T. add (f); T. policyall ();}}}

2. The scope of synchronization is to put and take two methods in this example. The irrelevant work of cooking and food cannot be put in the protected scope.

3. Participants-Volume Ratio

The relationship between the proportion of producers and consumers and the maximum number of dishes that can be placed on a table is an important factor affecting performance. If too many producers are waiting, increase or decrease the number of consumers. Otherwise, increase or decrease the number of consumers.

In addition, if the table has enough capacity, it can greatly improve the program performance. In this case, it can increase the number of producers and consumers at the same time, but when you have enough capacity, you often need enough physical memory.

Multi-thread programming-Practice (2)

This section continues the discussion in the previous section.

  [A thread will release the lock on the object after it enters the object Lounge (the wait () method of the object is called)]For this reason. In synchronization, unless necessary, you do not apply the thread. Sleep (long l) method, because the sleep method does not release the object lock.

This is an extremely bad moral character. You do nothing yourself and enter the sleep state, but seize the monitoring lock of the competing object to prevent other threads that need the monitoring lock of this object from running, simply put, it is an act of extreme selfishness. But I have seen that many programmers still have the code to call sleep in the synchronous method.

See the following example:

package debug;class SleepTest{  public synchronized void wantSleep(){    try{      Thread.sleep(1000*60);    }catch(Exception e){}    System.out.println("111");  }    public synchronized void say(){    System.out.println("123");  }}class T1 extends Thread{  SleepTest st;  public T1(SleepTest st){    this.st = st;  }  public void run(){    st.wantSleep();  }}class T2 extends Thread{  SleepTest st;  public T2(SleepTest st){    this.st = st;  }  public void run(){    st.say();  }}public class Test {    public static void main(String[] args) throws Exception{      SleepTest st = new SleepTest();      new T1(st).start();      new T2(st).start();    }}

We can see that after the instance of thread T1 runs, the current thread grabs the lock of the St instance and then enters sleep. It does not run to system until it has slept for 60 seconds. out. println ("111"); then the run method is completed, and the monitoring lock on the st is released, so that the instance of thread T2.

If we change the wantsleep method:

  public synchronized void wantSleep(){    try{      //Thread.sleep(1000*60);      this.wait(1000*60);    }catch(Exception e){}    System.out.println("111");  }

We can see that the thread where the T2 instance is located immediately gets a running opportunity, first prints 123, and the thread where the T1 instance is located is still waiting until 60 seconds after running to system. out. println ("111"); method.

Therefore, calling the wait (long l) method not only blocks the current thread from running within the specified time, but also gives other competing threads a chance to run, how can this benefit not harm yourself? This is also the principle that conscientious programmers should follow.

After a thread calls the wait (long l) method, if the thread continues to run, you cannot know whether it is waiting for time to finish or is awakened by other threads during the wait process, if you are very concerned that it must wait for enough time to execute a task, rather than waiting for it to be awakened halfway, there is a method that is not very accurate:

Long L = system. system. currenttimemillis (); wait (1000); // prepare to wait for 1 second for the current thread while (system. system. currenttimemillis ()-l) <1000) // It indicates that it has not waited until 1 second. // It makes other threads wake up wait (1000-(system. system. currenttimemillis ()-l); // wait for the remaining time.

This method is not very accurate, but it can basically achieve the goal.

So in the synchronization method, unless you know exactly what you are doing and want to do so, you have no reason to use sleep. The wait method is enough to achieve your goal. However, if you are a very conservative person, after seeing the above paragraph, you are absolutely disgusted with the sleep method, and are determined not to sleep, so in non-synchronous methods (there are no competing objects with other threads), what should you do if you want the current thread to block for a certain period of time before running? (This is completely a trick. You should apply sleep properly in non-synchronous methods, but if you do not need sleep, do it like this)

    public static mySleep(long l){        Object o = new Object();        synchronized(o){            try{                o.wait(l);                }catch(Exception e){}        }    }

Don't worry, no one can call o. Policy [all] outside of this method, so o. Wait (l) will wait until the set time to complete the operation.

[Use of virtual locks]

Simply put, the virtual lock does not call the Synchronized Method (which is equivalent to synchronized (this) or does not call synchronized (this ), in this way, only one thread can run all the threads that call the synchronous methods on this instance. That is to say:

If a class has two Synchronization Methods m1 and m2, only one thread that can call the M1 Method on two or more lines can run, that is, the two calls M1 respectively, only one thread of M2 can run. Of course, there is no competition for non-synchronous methods. The non-synchronous method of this object can be called by any thread after a thread obtains the monitoring lock of this object.

In most cases, this situation may occur. When multiple threads call M1, one resource needs to be protected. When multiple threads call m2, another resource needs to be protected, if we set M1 and M2 as synchronization methods. The two threads that call the two methods respectively do not conflict, but they both need to obtain the Lock of this instance (the synchronous method is to synchronize this), which leads to unnecessary competition.

Therefore, virtual locks should be used here.

The objects protected by M1 and M2 methods are passed in as attributes A1 and A2. Then, the synchronization block for the synchronization method is changed to A1 and A2, respectively, in this way, there will be no competition when different threads call these two methods. Of course, if both M1 and M2 Methods operate on the same protected object, the two methods should still be used as synchronization methods. This is also one of the reasons for synchronizing methods or using synchronization blocks.

package debug;class SleepTest{  public synchronized void m1(){    System.out.println("111");    try{      Thread.sleep(10000);    }catch(Exception e){}  }    public synchronized void m2(){    System.out.println("123");      }}class T1 extends Thread{  SleepTest st;  public T1(SleepTest st){    this.st = st;  }  public void run(){    st.m1();  }}class T2 extends Thread{  SleepTest st;  public T2(SleepTest st){    this.st = st;  }  public void run(){    st.m2();  }}public class Test {    public static void main(String[] args) throws Exception{      SleepTest st = new SleepTest();      new T1(st).start();      new T2(st).start();    }}

In this example, we can see that two threads call the M1 and M2 methods of the St instance respectively, but competition is generated because they both need to obtain the st monitoring lock. T2 instances can only run after T1 is completed (10 seconds interval ). Assume that the M1 method needs to operate on a file F1, And the M2 method needs to operate on a file F2. Of course, we can synchronize F1 and F2 in the method, but we do not know F2 yet, whether F2 exists. If it does not exist, we synchronize a null object. We can use the virtual lock:

Package debug; Class sleeptest {string vlock1 = "vlock1"; string vlock2 = "vlock2"; Public void M1 () {synchronized (vlock1) {system. out. println ("111"); try {thread. sleep (10000);} catch (exception e) {}// action F1 }} public void m2 () {synchronized (vlock2) {system. out. println ("123"); // action F2 }}} class T1 extends thread {sleeptest st; Public T1 (sleeptest st) {This. st = sT;} public void run () {St. m1 () ;}} class T2 extends thread {sleeptest st; Public T2 (sleeptest st) {This. st = sT;} public void run () {St. m2 () ;}} public class test {public static void main (string [] ARGs) throws exception {sleeptest ST = new sleeptest (); New T1 (ST ). start (); New T2 (ST ). start ();}}

We can see two threads that call m1 and m2 respectively. Because they obtain the monitoring locks of different objects, they run normally without any competition, only when both threads call M1 or m2 at the same time will blocking occur.

Multi-thread programming-Practice (III)

[A deep understanding of thread objects and threads, threads and runtime environments]

In the first section of the basic article, I emphasized that to understand multi-threaded programming, the first two concepts are thread objects and threads. Now let's have a deep understanding of the relationships between thread objects, threads, and runtime environments, and find out the roles of runnable and thread.

 

On the Java platform, the serialization mechanism is a very important mechanism. If you cannot understand and be familiar with the serialization mechanism, you cannot be called a Java programmer.

On the Java platform, why are some objects serializable, but some objects cannot be serialized?

An object that can be serialized is simply an object that can be copied (meaning that it can be reconstructed by a certain mechanism). Such an object is a combination of some data in the memory. This object can be fully reflected by a combination of a certain position and sequence.

Some objects are related to the current environment. They reflect the current running environment and time sequence, so they cannot be sequenced. Otherwise, they cannot be restored in other environments and time sequences ".

For example, a socket object:

Socket sc = new Socket("111.111.111.111",80);

This SC object indicates a physical connection established between the host that is currently running this code and port 80 with an IP address of "111.111.111.111". If it is serialized, so how can it be restored on another host at another time? Once the socket connection is disconnected, it does not exist and cannot be reproduced by another host at another time. The original SC object is no longer reproduced.

Thread objects are also non-serializable objects. When we create a new thread, We have initialized the information related to the running environment of the current thread object, and the thread scheduling mechanism, security mechanisms and other information only specific to the current runtime environment. If it is serialized, the information of the originally initialized runtime environment during running in another environment cannot be run in the new environment. If you want to reinitialize it, it is no longer the original thread object.

Just as socket encapsulates the connections between two hosts, they are not already linked to transfer data. To transmit data, you also need to getinputstream and getoutputstream, and read and write to start a real "Data Connection" between the two hosts ".

After a thread object is created, it only has a token for "running" and is just a "thread object ". Only when it calls start () Will the current environment allocate it a "space" for running, so that this code can start to run. This running "space" is called a real "Thread ". That is to say, the real thread refers to the "event" currently being executed ". Is the running environment of the thread object.

After understanding the above concepts, let's take a look at why there are runnable and thread objects in Java.

1. In terms of design techniques, Java cannot call method pointers to implement callback. Therefore, the interface is used to restrict the implementers from providing matching methods forcibly, and the instance of the class implementing this interface is provided to the caller as a parameter, which is an important means to implement callback on the Java platform.

2. But from the perspective of actual operations, algorithms and data do not depend on any environment. Therefore, we encapsulate the algorithms and data in the operations we want to implement into a run method (because the algorithms are a part of the data, I call them data merging ), it can separate the logic of data from the environment. So that programmers only care about how to implement the operations they want to do, rather than the environment in which they are located. When you really need to run it, pass the "operation" to a thread object in the current environment.

3. This is the most important reason:Data sharing

Because a thread object does not run for multiple times. Therefore, data is stored in the thread object and won't be accessed by multiple threads at the same time. To put it simply:

    class T extends Thread{        Object x;        public void run(){//......;}    }    T t = new T();

After instance t of T runs, the data X contained in T can only be shared by one T. Start () object unless declared as static object X;

Instance data of one t can only be accessed by one thread. It means "a data instance corresponds to a thread ".

For example

  class T extends Thread{        private Object x;        public T(Object x){            this.x = x;        }        public void run(){//......;}    }

In this way, we can pass an X object to multiple thread objects, and multiple threads operate on one data together. That is, "a data instance corresponds to multiple threads ".

Now we can better organize the data and encapsulate the Data Object X to be operated and the operation to be performed into the runnable run () method, transmits the runnable instance from the external to multiple thread objects. In this way, we have:

[Multiple threads of an object]

This is an important concept of the thread pool that we will introduce in the future.

Multi-thread programming-Practice (4)

To put it bluntly, at least half believe that the thread's "interruption" is to stop the thread. If you think so too, you are not getting started with multi-threaded programming.

In Java, the thread interrupt (Interrupt) only changes the thread interrupt state. As for the result of the change in the interrupt state, it cannot be determined, sometimes it is the only way to let the stopped thread continue execution. Instead of stopping the thread, it is a means of continuing to execute the thread.

For a thread that executes the general logic, if its interrupt () method is called, there is no impact on this thread. For example, thread a is executing: While (condition) x ++; if other threads call. interrupt (); the thread running on Object A will not be affected. If it tests the interrupt status of object A in other threads, it has changed, but it does not stop the thread running. Calling the interrupt () method on a thread object really affects the wait, join, and sleep methods. Of course, these three methods include their overload methods.

Note:[The above three methods will throw interruptedexception]Remember this sentence. I will repeat it below. After a thread calls interrupt (), it will not throw the interruptedexception exception, so you can see that interrupt () does not throw this exception, So I mentioned that if thread a is executing the while (condition) X ++; you call. interrupt (); then the thread continues to run normally.

However, if a thread is called interrupt (), its status is interrupted. This status changes the running result of a thread that is executing wait, join, and sleep.

1. For the thread waiting for wake-up by Y/notifyall in wait, the thread has actually paused because it is in the lounge of a certain object, in this case, if its interrupt status is changed, it will throw an exception. This interruptedexception exception is not thrown by the thread, but is the wait method, that is, the wait method of the object constantly checks the status of the thread on the object, if the status of a thread is set to interrupted, interruptedexception will be thrown, which means that the thread can no longer wait, and the meaning is equivalent to waking it up.

The only difference here is that the thread awakened by Y/all will continue to execute the statements below the wait, while the thread interrupted in the wait will give control to the catch statement. Some normal logic should be put into catch to run. However, sometimes this is the only method. For example, if a thread a is waiting to wake up in the wait of a certain object B, other threads must obtain the monitoring lock of object B before calling B. Y () [all], otherwise you will not be able to wake up thread A, but any thread can call a unconditionally. interrupt. Only the wake-up logic should be put in catch. Of course, like running y/All, the condition for continuing to execute thread a still needs to wait for the monitoring lock of object B to be obtained.

2. For threads in sleep, if you call the thread. sleep (one year); now you regret it. To wake it up earlier, calling the interrupt () method is the only way to change its interrupt status, it transfers control from sleep to the catch statement that handles exceptions, and then converts the process from catch to the normal logic. Similarly, you can handle the threads in the join operation as well.

For books that generally introduce the multithreading mode, they will introduce this: when a thread is interrupted, an exception will be thrown when it enters the wait, sleep, and join method. Yes, but what does it mean? If you know that the thread is in the interrupted state, why do you need to let it enter these three methods? Of course, this is sometimes necessary, but most of the time there is no reason to do so, so I have mainly introduced calling interrupt () on the thread that has already called these three methods () method to restore it from the "paused" status. This recovery includes two purposes:

I,[Thread execution can be continued]That is, to entertain the wake-up logic in the catch statement, or to convert the catch statement back to the normal logic. In short, it is from the wait, sleep, join pause State to live.

II,[Thread running can be stopped directly]Of course, nothing is processed in the catch, or return, then the mission of the current thread is completed, so that the above "pause" status can be immediately "STOPPED ".

  Interrupt thread

With the [thread interruption] in the previous section, we can proceed with [thread interruption. This is definitely not a text game. The reason is that "thread interruption" does not guarantee "thread interruption", so I have to explain it in two sections. Here, the "thread interruption" means "stop the thread", but why not "stop the thread? The thread has a clear Stop method, but it is opposed to the use, so remember not to mention the thread stop statement in Java, forget it! However, as an introduction to thread knowledge, I still want to tell you why you don't need to "stop the thread.

  [Stop a thread]

When the stop () method is called on a thread object, the thread running on this thread object will immediately stop and throw a special threaddeath () exception. The "immediate" here is too "immediate". It is like a child playing with his own toys. When the adults say they are going to bed, they will immediately go to bed with toys everywhere. Such a child is not good.

Assume that a thread is executing:

synchronized void { x = 3; y = 4;}

Because the method is synchronous, X and Y are always assigned values when multiple threads access the data. If a thread is running to X = 3, stop () is called () method, even in the synchronization block, it simply stops, resulting in incomplete disability data. The most basic condition in multi-threaded programming must ensure data integrity. Therefore, please forget the stop method of the thread. In the future, we will never say "stop the thread" again.

How can I end a thread?

  [Interrupt thread]

To end a thread, we need to analyze the running status of the thread. That is, what the thread is doing. If the child does not do anything, let him go to bed immediately. If the child is playing with his toys, we need to let it clean up and go to bed.

Therefore, a thread should have three phases from running to actually ending:

  1. Normal operation.
  2. Process the work before the end, that is, prepare to finish.
  3. End and exit.

In my JDBC column, I reminded n times that, after an SQL logic is completed, either way you must disable connnection IN THE finally clause. Similarly, the job before the end of the thread should be completed in finally to ensure that the thread must be executed before exiting:

Try {logic} catch () {} finally {cleaning work}

So how can we end a thread? Since stop cannot be called, only the interrupt () method is available. However, the interrupt () method only changes the running state of the thread. How can I let it exit? For general logic, as long as the thread state has been interrupted, we can let it exit, so such a statement can ensure that the thread can end running after being interrupted:

While (! Isinterrupted () {normal logic}

In this way, if the thread is called the interrupt () method and isinterrupted () is true, the thread will exit the operation. However, if the thread is executing the wait, sleep, and join methods and you call the interrupt () method, the logic is incomplete.

If an experienced programmer processes the end of thread running:

Public void run () {try {While (! Isinterrupted () {working properly} catch (exception e) {return;} finally {cleanup }}

We can see that if the thread execution logic is set to true after innterrupt is called and isinterrupted () is set to true, after the loop is exited, the cleanup is completed, even if the thread is in the wait, sleep, join, it also throws an exception and exits after cleaning.

This looks very good, and the thread is fully working according to the most defined ideas. However, not every programmer has this idea. What if he is smart enough to handle exceptions? In fact, many or most programmers will do this:

Public void run () {While (! Isinterrupted () {try {working properly} catch (exception e) {// nothing} finally {}}}}

Think about what would happen to a sleep thread after calling interrupt? The wait method checks that isinterrupted () is true and throws an exception, but you have not processed it. The status of a thread that throws interruptedexception is immediately set to non-interrupted. If the catch statement does not handle exceptions, isinterrupted () is false in the next loop, the thread continues to run. You may throw an exception n times and cannot stop the thread.

So how can we ensure that the thread is actually stopped? During thread synchronization, we have a "double check", which can ensure the real synchronization control of the thread on the basis of Improving the efficiency. So I call the correct exit method of the thread "Double secure exit", that is, it does not take isinterrupted () as the loop condition. A tag is used as the cyclic condition:

Class mythread extend thread {private Boolean isinterrupted = false; // you need to modify public void interrupt () {isinterrupted = true; super. interrupt ();} public void run () {While (! Isinterrupted) {try {working properly} catch (exception e) {// nothing} finally {}}}}

Can I try this program correctly?

There are still many things to say about this program. come here first.

The go deep into Java column is reprinted from axman, A dev2dev user.

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.