Home  >  Article  >  Java  >  Detailed explanation of starting, interrupting or terminating threads in Java multi-threaded programming

Detailed explanation of starting, interrupting or terminating threads in Java multi-threaded programming

高洛峰
高洛峰Original
2017-01-05 15:37:101427browse

Thread startup:
1. Description of the difference between start() and run()
start(): Its function is to start a new thread, and the new thread will execute the corresponding run() method. start() cannot be called repeatedly.
run(): run() is just like an ordinary member method and can be called repeatedly. If you call run() alone, run() will be executed in the current thread and a new thread will not be started!
The following is explained with code.

class MyThread extends Thread{
  public void run(){
    ...
  }
};
MyThread mythread = new MyThread();

mythread.start() will start a new thread and run the run() method in the new thread.
Mythread.run() will directly run the run() method in the current thread and will not start a new thread to run run().

2. Example of the difference between start() and run()
Below, a simple example is used to demonstrate the difference between them. The source code is as follows:

// Demo.java 的源码
class MyThread extends Thread{
  public MyThread(String name) {
    super(name);
  }
 
  public void run(){
    System.out.println(Thread.currentThread().getName()+" is running");
  }
};
 
public class Demo {
  public static void main(String[] args) {
    Thread mythread=new MyThread("mythread");
 
    System.out.println(Thread.currentThread().getName()+" call mythread.run()");
    mythread.run();
 
    System.out.println(Thread.currentThread().getName()+" call mythread.start()");
    mythread.start();
  }
}

Running results:

main call mythread.run()
main is running
main call mythread.start()
mythread is running

Result description:
(1) Thread.currentThread().getName() is used to get the name of the "current thread". The current thread refers to the thread that is being scheduled for execution in the CPU.
(2) mythread.run() is called in "main thread main", and the run() method runs directly on "main thread main".
(3) mythread.start() will start the "thread mythread". After the "thread mythread" is started, the run() method will be called; at this time, the run() method is running on the "thread mythread".

Interruption and termination of threads

1. Thread interruption: interrupt()
The function of interrupt() is to interrupt this thread.
This thread is allowed to interrupt itself; when other threads call the interrupt() method of this thread, they will check the permissions through checkAccess(). This may throw a SecurityException.
If this thread is in a blocked state: calling the thread's wait(), wait(long) or wait(long, int) will make it enter the waiting (blocked) state, or calling the thread's join(), join(long) ), join(long, int), sleep(long), sleep(long, int) will also put it into a blocking state. If the thread calls its interrupt() method while it is blocked, its "interrupted status" will be cleared and an InterruptedException will be received. For example, a thread enters the blocked state through wait(), and then interrupts the thread through interrupt(); calling interrupt() will immediately set the thread's interrupt flag to "true", but because the thread is in the blocked state, the "interrupt flag" " will be cleared to "false" immediately, and at the same time, an InterruptedException will be generated.
If a thread is blocked in a Selector and is interrupted by interrupt(); the thread's interrupt flag will be set to true, and it will return immediately from the selection operation.
If it does not fall into the above situation, then when the thread is interrupted through interrupt(), its interrupt flag will be set to "true".
Interrupting a "terminated thread" does not result in any operation.

2. Thread termination
The stop() and suspend() methods in Thread are recommended not to be used due to their inherent insecurity!
Below, I will first discuss the termination methods of threads in the "blocked state" and "running state" respectively, and then summarize a general method.
1. Terminate the thread in the "blocked state"
Usually, we terminate the thread in the "blocked state" through "interruption".
When the thread enters the blocking state due to being called by sleep(), wait(), join() and other methods; if the thread's interrupt() is called at this time, the thread's interrupt flag is set to true. Because it is in a blocked state, the interrupt mark will be cleared and an InterruptedException will be generated. The thread can be terminated by placing InterruptedException until appropriate. The form is as follows:

@Override
public void run() {
  try {
    while (true) {
      // 执行任务...
    }
  } catch (InterruptedException ie) {
    // 由于产生InterruptedException异常,退出while(true)循环,线程终止!
  }
}

Description: Continuously execute tasks in while(true). When the thread is in When in the blocking state, the calling thread's interrupt() generates an InterruptedException interrupt. The interrupt is captured outside while(true), thus exiting the while(true) loop!
Note: The capture of InterruptedException is generally placed outside the while(true) loop body, so that the while(true) loop is exited when an exception occurs. Otherwise, InterruptedException is within the while(true) loop body, and additional exit processing needs to be added. The form is as follows:

@Override
public void run() {
  while (true) {
    try {
      // 执行任务...
    } catch (InterruptedException ie) {
      // InterruptedException在while(true)循环体内。
      // 当线程产生了InterruptedException异常时,while(true)仍能继续运行!需要手动退出
      break;
    }
  }
}

Description: The above InterruptedException exception is captured within whle(true). When an InterruptedException exception occurs, it is still in the while(true) loop body outside of being handled by catch; to exit the while(true) loop body, additional operations to exit while(true) are required.
2. Terminate the thread in the "running state"
Usually, we terminate the thread in the "running state" by "marking". Among them, "interruption mark" and "additional addition mark" are included.
(1) Terminate the thread through "interrupt mark".
The form is as follows:

@Override
public void run() {
  while (!isInterrupted()) {
    // 执行任务...
  }
}

说明:isInterrupted()是判断线程的中断标记是不是为true。当线程处于运行状态,并且我们需要终止它时;可以调用线程的interrupt()方法,使用线程的中断标记为true,即isInterrupted()会返回true。此时,就会退出while循环。
注意:interrupt()并不会终止处于“运行状态”的线程!它会将线程的中断标记设为true。
(2) 通过“额外添加标记”。
形式如下:

private volatile boolean flag= true;
protected void stopTask() {
  flag = false;
}
 
@Override
public void run() {
  while (flag) {
    // 执行任务...
  }
}

   

说明:线程中有一个flag标记,它的默认值是true;并且我们提供stopTask()来设置flag标记。当我们需要终止该线程时,调用该线程的stopTask()方法就可以让线程退出while循环。
注意:将flag定义为volatile类型,是为了保证flag的可见性。即其它线程通过stopTask()修改了flag之后,本线程能看到修改后的flag的值。
综合线程处于“阻塞状态”和“运行状态”的终止方式,比较通用的终止线程的形式如下:

@Override
public void run() {
  try {
    // 1. isInterrupted()保证,只要中断标记为true就终止线程。
    while (!isInterrupted()) {
      // 执行任务...
    }
  } catch (InterruptedException ie) {
    // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。
  }
}

   

3. 终止线程的示例
interrupt()常常被用来终止“阻塞状态”线程。参考下面示例:

// Demo1.java的源码
class MyThread extends Thread {
 
  public MyThread(String name) {
    super(name);
  }
 
  @Override
  public void run() {
    try {
      int i=0;
      while (!isInterrupted()) {
        Thread.sleep(100); // 休眠100ms
        i++;
        System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
      }
    } catch (InterruptedException e) {
      System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
    }
  }
}
 
public class Demo1 {
 
  public static void main(String[] args) {
    try {
      Thread t1 = new MyThread("t1"); // 新建“线程t1”
      System.out.println(t1.getName() +" ("+t1.getState()+") is new.");
 
      t1.start();           // 启动“线程t1”
      System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
 
      // 主线程休眠300ms,然后主线程给t1发“中断”指令。
      Thread.sleep(300);
      t1.interrupt();
      System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
 
      // 主线程休眠300ms,然后查看t1的状态。
      Thread.sleep(300);
      System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

   

运行结果:

t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop 1
t1 (RUNNABLE) loop 2
t1 (TIMED_WAITING) is interrupted.
t1 (RUNNABLE) catch InterruptedException.
t1 (TERMINATED) is interrupted now.

   

结果说明:
(1) 主线程main中通过new MyThread("t1")创建线程t1,之后通过t1.start()启动线程t1。
(2) t1启动之后,会不断的检查它的中断标记,如果中断标记为“false”;则休眠100ms。
(3) t1休眠之后,会切换到主线程main;主线程再次运行时,会执行t1.interrupt()中断线程t1。t1收到中断指令之后,会将t1的中断标记设置“false”,而且会抛出InterruptedException异常。在t1的run()方法中,是在循环体while之外捕获的异常;因此循环被终止。
我们对上面的结果进行小小的修改,将run()方法中捕获InterruptedException异常的代码块移到while循环体内。

// Demo2.java的源码
class MyThread extends Thread {
 
  public MyThread(String name) {
    super(name);
  }
 
  @Override
  public void run() {
    int i=0;
    while (!isInterrupted()) {
      try {
        Thread.sleep(100); // 休眠100ms
      } catch (InterruptedException ie) {
        System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
      }
      i++;
      System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
    }
  }
}
 
public class Demo2 {
 
  public static void main(String[] args) {
    try {
      Thread t1 = new MyThread("t1"); // 新建“线程t1”
      System.out.println(t1.getName() +" ("+t1.getState()+") is new.");
 
      t1.start();           // 启动“线程t1”
      System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
 
      // 主线程休眠300ms,然后主线程给t1发“中断”指令。
      Thread.sleep(300);
      t1.interrupt();
      System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
 
      // 主线程休眠300ms,然后查看t1的状态。
      Thread.sleep(300);
      System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

   

运行结果:

t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop 1
t1 (RUNNABLE) loop 2
t1 (TIMED_WAITING) is interrupted.
t1 (RUNNABLE) catch InterruptedException.
t1 (RUNNABLE) loop 3
t1 (RUNNABLE) loop 4
t1 (RUNNABLE) loop 5
t1 (TIMED_WAITING) is interrupted now.
t1 (RUNNABLE) loop 6
t1 (RUNNABLE) loop 7
t1 (RUNNABLE) loop 8
t1 (RUNNABLE) loop 9
...

   

结果说明:
程序进入了死循环!
为什么会这样呢?这是因为,t1在“等待(阻塞)状态”时,被interrupt()中断;此时,会清除中断标记[即isInterrupted()会返回false],而且会抛出InterruptedException异常[该异常在while循环体内被捕获]。因此,t1理所当然的会进入死循环了。
解决该问题,需要我们在捕获异常时,额外的进行退出while循环的处理。例如,在MyThread的catch(InterruptedException)中添加break 或 return就能解决该问题。
下面是通过“额外添加标记”的方式终止“状态状态”的线程的示例:

// Demo3.java的源码
class MyThread extends Thread {
 
  private volatile boolean flag= true;
  public void stopTask() {
    flag = false;
  }
 
  public MyThread(String name) {
    super(name);
  }
 
  @Override
  public void run() {
    synchronized(this) {
      try {
        int i=0;
        while (flag) {
          Thread.sleep(100); // 休眠100ms
          i++;
          System.out.println(Thread.currentThread().getName()+" ("+this.getState()+") loop " + i);
        }
      } catch (InterruptedException ie) {
        System.out.println(Thread.currentThread().getName() +" ("+this.getState()+") catch InterruptedException.");
      }
    }
  }
}
 
public class Demo3 {
 
  public static void main(String[] args) {
    try {
      MyThread t1 = new MyThread("t1"); // 新建“线程t1”
      System.out.println(t1.getName() +" ("+t1.getState()+") is new.");
 
      t1.start();           // 启动“线程t1”
      System.out.println(t1.getName() +" ("+t1.getState()+") is started.");
 
      // 主线程休眠300ms,然后主线程给t1发“中断”指令。
      Thread.sleep(300);
      t1.stopTask();
      System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");
 
      // 主线程休眠300ms,然后查看t1的状态。
      Thread.sleep(300);
      System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}

   

运行结果:

t1 (NEW) is new.
t1 (RUNNABLE) is started.
t1 (RUNNABLE) loop 1
t1 (RUNNABLE) loop 2
t1 (TIMED_WAITING) is interrupted.
t1 (RUNNABLE) loop 3
t1 (TERMINATED) is interrupted now.

   


更多详解Java多线程编程中线程的启动、中断或终止操作相关文章请关注PHP中文网!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn