学习JAVA多线程编程 --- 《JAVA多线程编程核心技术》第1章 Java多线程技能 笔记

停止线程

在Java中有3种方法可以终止正在运行的线程:

  1. 使用退出标识,使线程正常退出,也就是当run方法完成后线程终止。
  2. 使用stop方法强行终止线程,这个方法是不安全的。stop和suspend及resume一样,都是作废过期的方法,使用它们可能产生不可预料的结果。
  3. 使用interrupt方法中断线程。

调用interrupt()方法可以在当前线程中打个停止的标记,这个方法不会真的停止线程。interrupted()是个静态方法,是用来测试当前线程是否已经中断。线程的中断状态也是由该方法清除。(如果连续两次调用该方法,则第二次调用将返回false)。isInterrupted不是静态方法,是用来测试线程Thread对象是否已经是中断状态,但不清除状态标志。

方法一:异常法

在促发点调用thread.interrupt(),在run()方法里通过调用this.interrupted()对中断进行检测,如果结果为true的话抛出InterruptedException().

public void run() {
  try {
    while (true) {
      // ...
      if (this.interrupted()) {
        throw new InterruptedException();
        // return;
      }
      // ...
    }
  } catch (InterruptedException e) {
    // now the this.interrupted() will be reset as false
  }
}

这样可以跳出所定义的循环而达到终止thread的效果。或是直接通过return来实现停止线程的效果。还是推荐使用抛异常的方法来实现线程的停止,因为在catch块中还可以将异常向上抛,是线程停止的事件得以传播。

这种方法也同样适用于在沉睡的thread,sleep的方法有自带检测interrupted()的功能,如果在sleep状态下停止某一线程,会进入catch语句,并且清除停止状态值,使之变成false。

综上所述,可以通过this.interrupted()来检测并清除中断状态,或是通过sleep自带检测功能两种方法跳出循环来结束run方法。

方法二:暴力stop

stop方法会抛出ThreadDeath的异常,可以强制让线程停止,但是有可能会使一些清理性的工作得不到完成。会对锁定的对象进行解锁,可能导致数据得不到同步处理。

暂停线程

暂停线程表示此线程还可以恢复运行。在Java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行。

try {
  MyThread thread = new MyThread();
  thread.start();
  // ...
  thread.suspend();
  // ...
  thread.resume();
  // ...
  thread.suspend();
  ...
} catch (InterruptedException e) {
  e.printStackTrace();
}

在使用suspend和resume方法时,如果使用不当,极易造成公共的同步对象的独占,使得其他线程无法访问共同同步对象。

public class SynchronizedObject {
  synchronized public void printString() {
    System.out.println("begin");
    if (Thread.currentThread().getName().equals("a")) {
      System.out.println("a thread forever suspend!");
      Thread.currentThread().suspend();
    }
    System.out.println("end");
  }
}

如果一个线程访问printString方法时满足if的条件,那么这个线程将永远被挂起。别的线程将无法在访问这个方法。Java常用的输出方法也是一个同步的方法。

public void println(long x) {
  synchronized (this) {
    print(x);
    newline();
  }
}

当一个线程正在打印时被suspend挂起的话,这个线程会使println方法一直呈暂停状态,并且不会释放锁(synchronized(this))。从而造成别的thread不在能使用println方法打印任何输出。

在使用suspend与resume方法时也容易出现因为线程的暂停而导致数据不同步的情况。

public void setValue(String u, Strign p) {
  this.username = u;
  if (Thread.currentThread().getName().equals("a")) {
    System.out.println("stop a thread!");
    Thread.currentThread().suspend();
  }
  this.password = p;
}

当前的线程被suspend挂起时,对于password的赋值将被延迟,而导致数据不同步。

yield方法:放弃当前的CPU资源,将它让给其他的任务去占用CPU执行时间。这里放弃的时间是不确定的,有可能刚刚放弃,马上又获得CPU时间片。

线程的优先级

JAVA可以使用setPeriority()方法来设置线程的优先级,通过设置可以使“线程规划器”确定下次选择哪一个线程来优先执行。优先级较高的线程得到的CPU资源比较多,CPU会优先执行优先级较高的线程对象中的任务。优先级分为1~10个等级,小于1或大于10,JDK会抛出异常IllegalArgumentException()。在JDK的预设的优先级为:

public final static int MIN_PRIORITY  = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY  = 10;

线程的优先级与代码执行顺序无关。并且线程的优先级还具有“随机性”,也就是优先级较高的线程不一定每次都先执行。

守护线程(Daemon):是一种特殊的线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。任何一个守护线程都是整个JVM中所有非守护线程的“保姆”,只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才随着JVM一同结束工作。守护线程最典型的应用就是GC(垃圾回收站)。守护线程可以通过setDaemon(true)来设置,当当前的线程执行完毕是,守护线程也会跟着结束。

你可能感兴趣的:(学习JAVA多线程编程 --- 《JAVA多线程编程核心技术》第1章 Java多线程技能 笔记)