线程的其他方法
1. 终止线程
一般来说线程的执行完毕就会结束,无需手动关闭。但当我们需要手动杀死一个正在运行的线程。可以通过一些方法。
stop方法(废弃)
1 2 3 4 5
| # stop()方法不推荐使用 因为stop()方法太暴力,会强制杀死线程。
这就类似于: 你正在写文档,突然停电,文档没有保存。 在程序运行过程中,强制杀死线程,线程还没有来得及保存上下文就结束了。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Demo1 {
public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { int i = 0; while(true){ System.out.println("i = " + i); i++; } } });
thread.start(); System.out.println("线程开始执行"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }
thread.stop(); System.out.println(); System.out.println("线程结束"); } }
|

2.中断线程
中断在计算机中是一个非常重要的机制。在多线程中,他是一种更好去中止线程的机制。我们可以通过与stop()做对比。stop()是强制杀死线程,不管当前的线程在做什么。而中断机制不会杀死线程,而是给线程发送一个通知,告诉线程,"你可以终止了"。之后,线程在接收到这个通知后如何处理,由线程自己确定。
isInterrupted()方法
1 2
| isInterrupted()是一个实例方法,它通过检查中断标志位,判断当前线程是否被中断。 当前线程被中断时为true
|
interrupted()方法
1
| interrupted()方法是一个静态方法,返回boolean类型,也是用来判断当前的线程是否被中断,但是同时会清楚当前线程的中断标志位
|
interrupt()方法
1 2 3 4 5 6
| interrupt()方法是一个实例方法,他通知线程中断,设置中断标志位为true,中断标志位表示当前线程已经被中断了,它不会中断一个正在运行的进程。
如果线程被Object.wait(),Thread.join(),Thread.sleep()方法阻塞,然后调用interrupt()方法。此时线程在检查中断标识是如果是true,那么该线程将抛出一个InterruptedException中断异常,并且在抛出异常后立即将线程的中断标识位清除,即重新设置为false。该线程必须事先预备好处理这个异常,从而提早地终结被阻塞状态。
抛出异常是为了线程从阻塞状态醒过来,并在结束线程前让程序员有足够的时间来处理中断请求。
|
1 2 3
| # 注意 synchronized在获得锁的过程中是不能被中断的。 调用interrupt()方法只是在目标线程中设置了中断标志位true。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class Demo2 { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { int i = 0; System.out.println(Thread.currentThread().isInterrupted()); while(!Thread.currentThread().isInterrupted()){ System.out.println("i = " + i); i++; } System.out.println(Thread.currentThread().isInterrupted()); } });
thread.start(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } thread.interrupt(); } }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Demo3 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread() { @Override public void run(){ while(true) { try { sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); this.interrupt(); }
if(this.isInterrupted()){ break; }
} } }; thread.start(); Thread.sleep(1000); thread.interrupt(); }
}
|

1 2 3 4
| # 注意 在main方法中调用thread.interrupt()方法,此时thread线程内部的中断标志位会置为true 然后会触发run方法内部的InterruptedException异常,所以运行结果中由异常输出,当触发InterruptedException异常时,线程内部的中断标志又会被清除(false)。 因此我们在catch()中调用了this.interrupt();将中断标志位设置为true。然后退出循环。
|
3.等待(wait)、通知(notify)
等待wait()和通知notify()这两个方法并不是Thread类中的方法,而是每个Object类中定义的。每一个对象都有这两个方法。
1 2 3
| public final native void wait(long timeout) throws InterruptedException; public final native void notify(); public final native void notifyAll();
|
1 2 3 4
| # 这两个方法只用于多线程之间的协作。
当在一个对象实例上调用wait()方法后,当前线程就会在这个对象上等待。 比如在线程1中调用object.wait()方法,那么线程1就会停止继续执行,转为等待状态。而当线程2调用object.notify()方法后,线程就会继续执行。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class waitNotifyDemo {
private static Object object = new Object();
public static void main(String[] args) throws InterruptedException { Thread thread1 = new Thread() { @Override public void run() { System.out.println("线程1开始"); synchronized (object){ System.out.println("线程1得到锁"); try { System.out.println("线程1等待并释放锁"); object.wait(); System.out.println("线程1等待结束并重新获得锁"); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("线程1结束"); } };
Thread thread2 = new Thread(new Runnable() { @Override public void run() { synchronized (object){ System.out.println("线程2开始 得到锁"); try { System.out.println("线程2睡眠5秒"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程2通知线程1结束等待"); object.notify(); System.out.println("线程2释放锁"); } System.out.println("线程2结束"); } });
thread1.start(); Thread.sleep(1000); thread2.start(); } }
|

1 2 3 4 5
| # 对wait和notify的分析 这两个方法并不能随便使用。它必须包含在对应的synchronize语句中。 无论是wait方法还是notify方法都需要获取目标独享的一个监视器。这样做的目的是使得其他等待在object对象的线程不至于因为线程1的休眠而全部无法执行。 # wait和sleep方法的对比 wait方法可以被唤醒,wait会释放目标对象的锁
|
时间 |
线程1 |
线程2 |
T1 |
得到锁 |
|
T2 |
执行wait |
|
T3 |
释放锁 |
|
T4 |
|
得到锁 |
T5 |
|
执行notify |
T6 |
|
释放锁 |
T7 |
得到锁 |
|
T8 |
… |
|
1 2 3 4 5
| # 理解wait和notify 当一个线程调用了object.wait()方法时,那么他就会进出object对象的等待队列。在这个队列中,可能会有多个线程,因为系统可能运行多个线程等待某一个对象。当object.notify()方法被调用时,他就会从这个队列中随机选择一个线程,并将其唤醒。这个选择是不公平的,随机的,并不会先等待线程就会优先被选择。
# notifyAll()方法 这个方法与notify()方法类似。他会唤醒在这个等待队列中所有等待的线程。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| class ThreadDemo1 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + " 没有拿到锁"); synchronized (waitNotifyDemo2.class){ try { System.out.println(Thread.currentThread().getName() + " 拿到锁"); System.out.println(Thread.currentThread().getName() + " 等待并释放锁"); waitNotifyDemo2.class.wait(); System.out.println(Thread.currentThread().getName() + " 重新得到锁"); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 释放锁"); } } }
public class waitNotifyDemo2 {
public static void main(String[] args) throws InterruptedException { ThreadDemo1 threadDemo = new ThreadDemo1();
Thread t1 = new Thread(threadDemo); Thread t2 = new Thread(threadDemo); Thread t3 = new Thread(threadDemo); Thread t4 = new Thread(threadDemo);
t1.start(); Thread.sleep(1000); t2.start(); t3.start(); t4.start();
Thread.sleep(2000); new Thread(new Runnable() { @Override public void run() { synchronized (waitNotifyDemo2.class){ waitNotifyDemo2.class.notify(); } } }).start();
synchronized (waitNotifyDemo2.class){ waitNotifyDemo2.class.notifyAll(); } }
}
|

4.挂起(suspend)和继续执行(resume)
在Thread类中,由两个方法,suspend()线程挂起、resume()线程继续执行。JDK中标注了这两个方法已经过时了,不推荐使用。因为suspend()方法去挂起线程不会释放任何锁资源,直到线程执行了resume方法。而且,对于被挂起的线程,从线程上的状态上看,依旧还是Runnable状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class ThreadDemo implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + " 挂起"); Thread.currentThread().suspend(); System.out.println(Thread.currentThread().getName() + " 继续执行"); } }
public class suspendResumeDemo1 {
public static void main(String[] args) throws InterruptedException { ThreadDemo threadDemo = new ThreadDemo();
Thread thread1 = new Thread(threadDemo); Thread thread2 = new Thread(threadDemo);
thread1.start(); Thread.sleep(1000); thread2.start();
thread1.resume(); thread2.resume(); }
}
|

5.等待线程结束(join)和谦让(yeild)
有时候,一个线程可能需要等另一个线程结束以后才执行。JDK中提供了join()这个方法来操作。yeild()方法是一个静态方法,一旦执行,它会让出CPU,之后,他会继续和其他线程竞争CPU
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class joinYeildDemo {
public static void main(String[] args) throws InterruptedException { Thread th = new Thread(new Runnable() { @Override public void run() {
try { System.out.println("th线程睡眠5秒"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }
int i = 0; for (;i<10;i++){ System.out.println("i = " + i); } } });
th.start(); th.join();
System.out.println("等待th线程完成"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0;
if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
|