wait和notify,保护性暂停模式

调用(notify\notifyAll,wait)等线程控制方法时,必须有两个前提
1:要在被synchronized关键字控制的同步代码块中,调用这些方法
2:调用者为当前的锁对象

wait,notify,notifyAll都是当前线程成为Monitor的Owner了,才可以调用
线程已经获得了锁,然后调用wait放弃(释放)了锁,到Monitor的waitSet中等待,阻塞
notify挑一个唤醒waitSet中的线程,notifyAll唤醒所有
被唤醒的线程(并不是立即继续执行,而是进入到EntryList中,等当前线程释放了锁,EntryList中的线程再进行竞争)

// 当前线程没有获得对象锁,调用wait会抛异常
IllegalMonitorStateException:if the current thread is not the owner of the object's monitor.
// ok
static final Object lock = new Object();
public static void main(String[] args) {
    synchronized (lock) { 	// 先要成为lock锁对象关联的monitor的owner
        try {				// 才能调用wait,进入monitor的waitSet
            lock.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
// error
static final Object lock = new Object();
public static void main(String[] args) {
    try {           // lock锁对象没有关联monitor,线程也没有成为monitor的owner
        lock.wait();// IllegalMonitorStateException
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
sleep是Thread的静态方法
wait是Object的实例方法,wait需要先获得对象锁,配合synchronized使用
sleep不会释放对象锁,wait会释放对象锁

保护性暂停(产生结果的线程和将来使用结果的线程是11对应的)

public class Main {
    public static void main(String[] args) {
    	// 共用一个guardedObject,产生的线程和使用的线程要11对应
        GuardedObject guardedObject = new GuardedObject();
        // t1线程会等待t2线程,直到拿到t2线程的结果
        new Thread(() -> {
            Object result = guardedObject.get();
            System.out.println(result);
        },"t1").start();
        new Thread(() -> {
            String data = "cwdf";
            guardedObject.complete(data);
        },"t2").start();
    }
}
// 线程间传递结果
class GuardedObject {
    private Object response; // 结果
    public Object get() {
        synchronized (this) {
            while(response == null){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return response;
        }
    }
    public void complete(Object response){
        synchronized (this){
            this.response = response;
            this.notifyAll();
        }
    }
}

join原理(等待线程的结束)

// t1.join()// 主线程陷入阻塞,等待t1线程运行结束
public final synchronized void join(final long millis) throws InterruptedException {
	if (millis > 0) {
		if (isAlive()) {
		    final long startTime = System.nanoTime();
		    long delay = millis;
		    do {
		        wait(delay);
		    } while (isAlive() && (delay = millis - TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
		}
	} else if (millis == 0) {
        while (isAlive()) {// 只要t1线程还活着
            wait(0);// 当前线程就睡觉
            // (当前线程执行join方法时,会为this对象即t1加锁.锁对象this\t1调用wait,所以当前线程就会睡觉(到Monitor的waitSet中))
        }
    } else {
        throw new IllegalArgumentException("timeout value is negative");
    }
}

保护性暂停模式,解耦,将GuardedObject放到信箱中

public class Main {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new People().start();// 3个等待收信
        }
        TimeUnit.SECONDS.sleep(1);
        // 每个邮件对应一个邮递员配送(1对1)
        for (Integer id : Mailboxes.getIds()) {
            new PostMan(id,"内容" + id).start();
        }
    }
}
// 居民
@Slf4j
class People extends Thread{
    @Override
    public void run() {
        GuardedObject guardedObject = Mailboxes.createGuardedObject();
        Object mail = guardedObject.get();
        log.info("收到信id:{},内容:{}",guardedObject.getId(),mail);
    }
}
// 邮递员
@Slf4j
@AllArgsConstructor
class PostMan extends Thread {
    private int id;
    private String mail;
    @Override
    public void run() {
        GuardedObject guardedObject = Mailboxes.getGuardedObject(id);
        log.info("送信id:{},内容:{}",id,mail);
        guardedObject.complete(mail);
    }
}
// 信箱(解耦等待和生产)
class Mailboxes {
    // 信箱小格子(编号,邮件)
    private static Map<Integer,GuardedObject> boxes = new Hashtable<>();
    private static int id = 1;
    private static synchronized int generateId(){
        return id++;
    }
    public static GuardedObject getGuardedObject(int id){
        return boxes.remove(id);
    }
    public static GuardedObject createGuardedObject(){
        GuardedObject guardedObject = new GuardedObject(generateId());
        boxes.put(guardedObject.getId(),guardedObject);
        return guardedObject;
    }
    // 所有要送的信的编号
    public static Set<Integer> getIds(){
        return boxes.keySet();
    }
}
// 线程间传递结果
@Data
class GuardedObject {
    private Integer id;
    private Object response; // 结果
    public GuardedObject(int id){
        this.id = id;
    }

    public Object get() {
        synchronized (this) {
            while(response == null){
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return response;
        }
    }
    public void complete(Object response){
        synchronized (this){
            this.response = response;
            this.notifyAll();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值