一、等待通知
但我们在使用多线程的时候,通常会遇到线程执行到某一个点的时候需要停止下来,等待其他线程执行,当其他线程执行到某一个点的时候,当前线程再来执行的情况。针对这种情况,我们就需要使用到wait()和notify()两个方法了,这两个方法分别是线程等待和唤醒线程。
但是我们要注意的一个点就是,这两个方法并不是线程API提供了,而是Object类提供的。具体的使用方法如下:
public class WaitAndNotifyTest {
private final static Object object = new Object();
public static class T1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() + " ,T1 start");
try {
System.out.println(System.currentTimeMillis() + " ,T1 begins to wait");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " ,T1 end");
}
}
}
public static class T2 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() + " ,T2 start");
System.out.println(System.currentTimeMillis() + " ,T2 begins to notify");
object.notify();
System.out.println(System.currentTimeMillis() + " ,T2 end");
}
}
}
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
t1.start();
t2.start();
}
}
线程运行的结果如下:
1506220107966 ,T1 start
1506220107966 ,T1 begins to wait
1506220107966 ,T2 start
1506220107967 ,T2 begins to notify
1506220107967 ,T2 end
1506220107967 ,T1 end
从上面的执行结果我们可以看出,T1处于开始执行并且当处于等待状态的时候,T2开始执行,并且T2唤醒T1的时候,直到T2释放了针对object的锁的时候才执行T1。
在这里我们需要明白的一个点是线程等待队列中会有很多线程都在等待,而线程唤醒就是随机唤醒一个线程,并不是先进入等待状态的线程最先被唤醒。但是当我们使用notifyAll
方法来对线程进行唤醒的时候,这个时候所有进入等待队列的线程都将被唤醒。
二、挂起和继续执行
在我们使用多线程的时候,会用到线程的挂起和执行。如果要让线程挂起,可以使用suspend(),要继续执行线程可以使用resume(),但是使用这两个方法来执行线程挂起和执行
出现如果一个线程被挂起,它也不会释放任何资源,其他线程也无法获得资源。具体示例如下:
package com.liutao.thread.chap1;
/**
* 〈一句话功能简述〉
* 〈功能详细描述〉
*
* @author LIUTAO
* @version 2017/9/26
* @see
*/
public class SuspendAndResume {
public static Object object = new Object();
static ChangeObjectThread changeObjectThread1 = new ChangeObjectThread("changeObjectThread1");
static ChangeObjectThread changeObjectThread2 = new ChangeObjectThread("changeObjectThread2");
public static class ChangeObjectThread extends Thread{
public ChangeObjectThread(String name){
super.setName(name);
}
@Override
public void run(){
synchronized (object){
System.out.printf("in "+getName()+"\n");
Thread.currentThread().suspend();
}
}
}
public static void main(String[] args) throws InterruptedException {
changeObjectThread1.start();
Thread.sleep(1000);
changeObjectThread2.start();
changeObjectThread1.resume();
changeObjectThread2.resume();
changeObjectThread1.join();
changeObjectThread2.join();
}
}
以上代码执行结果如下:
in changeObjectThread1
in changeObjectThread2
但是如果这个时候我们将changeObjectThread1.resume()这个方法注释掉,我们就会发现上面的输出结果仅仅只有第一行。这就是我们使用suspend()和resume()这两个方法带
来的坏处,这种方式来挂起和执行线程会导致资源不能够得到释放,另外一方面,如果在某些情况下一个线程的resume()比suspend()先执行,那么这个线程也不会得到正确地执
行。因此我们有如下的修改方式:
public class SuspendAndResume {
public static Object object = new Object();
public static class ChangeObjectThread extends Thread{
volatile boolean suspendme = false;
public void suspendMe(){
this.suspendme = true;
}
public void resumeMe(){
suspendme = false;
synchronized (this){
notify();
}
}
@Override
public void run(){
while(true){
synchronized (this){
while(suspendme){
try {
wait();
}catch (InterruptedException i){
i.printStackTrace();
}
}
}
synchronized (object){
System.out.println("in ChangeObjectThread");
}
Thread.yield();
}
}
}
public static class ReadObjectThread extends Thread{
@Override
public void run(){
while(true){
synchronized (object){
System.out.println("in ReadObjectThread");
}
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException {
ChangeObjectThread changeObjectThread = new ChangeObjectThread();
ReadObjectThread readObjectThread = new ReadObjectThread();
changeObjectThread.start();
readObjectThread.start();
Thread.sleep(10000);
changeObjectThread.suspendMe();
System.out.println("suspend changeObjectThread 2 sec");
Thread.sleep(20000);
System.out.printf("resume changeObjectThread");
changeObjectThread.resumeMe();
}
}
从上面的代码我们可以看出我们使用了wait()和notify()这两个方法加上suspendme标志来对线程进行控制。