线程自然终止:自然执行完或抛出未处理异常
Java中有3种方法可以使正在运行的线程终止运行:
1.使用退出标志使线程正常退出;
2.使用stop()方法强行终止线程,但这个方法不推荐使用,因为stop()和suspend(),resume()一样,都是作废的方法,使用它们会发生不可预料的结果;stop()会导致线程不会正确释放资源,suspend()容易导致死锁
3.使用interrupt() 方法中断线程;
suspend()死锁例子:
public class SuspendTest1 { private static class SynchronizedObject { public synchronized void printString() { System.out.println("begin --"); if (Thread.currentThread().getName().equals("thread-a")) { System.out.println("a线程 suspend.."); Thread.currentThread().suspend(); } System.out.println("end ---"); } } public static void main(String[] args) { try { SynchronizedObject object = new SynchronizedObject(); Thread thread1 = new Thread() { @Override public void run() { System.out.println(Thread.currentThread().getName()); object.printString(); } }; thread1.setName("thread-a"); thread1.start(); TimeUnit.SECONDS.sleep(1); Thread thread2 = new Thread() { @Override public void run() { System.out.println("thread2 start..."); object.printString(); System.out.println("thread2 end..."); } }; thread2.setName("thread-b"); thread2.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
当thread2运行到thread2 start...后,一致阻塞,用jstack查看,如下:
"thread-b" #12 prio=5 os_prio=0 tid=0x000000001d169800 nid=0x8658 waiting for monitor entry [0x000000001ddcf000] java.lang.Thread.State: BLOCKED (on object monitor) at com.example.SuspendTest1$SynchronizedObject.printString(SuspendTest1.java:12) - waiting to lock <0x000000076b5a9568> (a com.example.SuspendTest1$SynchronizedObject) at com.example.SuspendTest1$2.run(SuspendTest1.java:40) Locked ownable synchronizers: - None
线程状态转移图如下:
发现出现BLOCKED,在thread2调用object.printString()这里出现死锁;
出现这种情况是因为运行到println方法内部时,同步锁不释放;
public void println(String x) { synchronized (this) { print(x); newLine(); } }
Java线程是协作式,而非抢占式
抢占式:现行进程在运行过程中,如果有重要或紧迫的进程到达(其状态必须为就绪),则现运行进程将被迫放弃处理器,系统将处理器立刻分配给新到达的进程;如打开任务管理器终止一个进程;
Java协作式:调用一个线程的 interrupt() 方法中断一个线程,并不是强行关闭这个线程,将线程的中断标志位置为true,线程是否中断,由线程本身决定(类似人与人打招呼,但是对方回不回你又是另一回事);如下:
FutureTask<String> future = new FutureTask<>(new MyCallable()); Thread thread = new Thread(future); thread.start(); thread.interrupt(); //如果异步任务还没有完成,那么get()会阻塞,直到任务完成后才返回结果 System.out.println(future.get());
这里线程的中断有线程本身决定的;
isInterrupted() 判定当前线程是否处于中断状态
static方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false
方法里如果抛出InterruptedException,线程的中断标志位会被复位成false,如果确实是需要中断线程,要求我们自己在catch语句块里再次调用interrupt();