并发编程入门,关于wait()/notify(),sleep()的认识

关于wait方法

1. 带超时参数的wait

public final native void wait(long timeout) 
  • 该方法的主要作用是当前线程进入等待状态,但这的前提是,当前线程已经获取了某个对象锁。
  • 当线程进入等待状态后,可能会重新唤醒的条件有以下几种:
    1、另一个线程调用了当前对象锁的notify()或者notifyAll()方法;
    2、该线程的等待时间到达,如果是为零的话,这个条件失效;
    3、其他线程调用了该线程的interrupt()方法

wait的阻塞实现其实是当你调用时,当前线程会将自己置于该对象的等待集中,当线程被唤醒后,该线程就会从该对象的等待集中移除,然后重新被调度,竞争锁资源。当该线程争得锁资源后,则会对同步现场进行还原,并且执行同步代码块wait()语句往下的内容。

但是处于等待状态的线程其实也是可以被唤醒的,也就是spurious wakeup(虚假唤醒)。接比如当线程没有做出相应配合的情况下,interrupt()可以将处于等待状态的线程给打断,进入运行状态。但是此时线程的运行可能是和我们的代码行为互相违背的。又或者,wait( )超时,但是还是可能会不满足我们的程序行为。
所以,jdk中对于wait()的推荐实践是将其放在一个循环中,当条件不满足的情况下线程会继续进入等待。

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }

2、无参数的wait()

public final void wait() throws InterruptedException

该方法的实际实现如下:

public final void wait() throws InterruptedException {
    wait(0);
}

其实这里是调用了wait(long timeout),只不过传入参数的为零,相当于没有超时时间的限制,此时的线程被唤醒的条件有以下两种:

3、带纳秒参数的wait()方法

public final void wait(long timeout, int nanos) 

实际上等于

public final void wait(long timeout, int nanos) throws InterruptedException {
    if (timeout < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException(
                            "nanosecond timeout value out of range");
    }

    if (nanos > 0) {
        timeout++;
    }

    wait(timeout);
}

就是把纳秒当成一个毫秒去处理了,然后其它的和上述的wait()方法差不多。

关于notify方法

1、notify()
wait()方法会将线程设置于目标对象的等待集中,而notify()方法则是随机唤醒该等待集中的某个线程。
但是,被唤醒的线程能够重新争夺锁资源的前提是产生唤醒动作的线程放弃了锁资源。例如下面代码:

public class WaitNotify {
    public static void main(String[] args) {
        Object o = new Object();
        WaitThread waitThread = new WaitThread(o);
        NotifyThread notifyThread = new NotifyThread(o);
        System.out.println("The application is start!!");
        waitThread.start();
        notifyThread.start();

    }
}

class WaitThread extends Thread{

    private Object object;

    public WaitThread(Object object) {
        this.object = object;
    }

    @Override
    public void run() {
        synchronized (object) {
            System.out.println("The wait thread is start!!");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Integer index = 10;
            while (index -- > 0) {
                System.out.println("The wait thread is running!!");
            }
            System.out.println("The wait thread is stop!!");
        }
    }
}

class NotifyThread extends Thread{

    private Object object;

    public NotifyThread(Object object) {
        this.object = object;
    }

    @Override
    public void run() {
        synchronized (object) {
            System.out.println("The notify thread is start!!");
            object.notify();
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Integer index = 5;
            while (index -- > 0) {
                System.out.println("The notify thread is running!!");
            }
            System.out.println("The notify thread is stop!!");
        }
    }
}

输出结果:

The application is start!!
The wait thread is start!!
The notify thread is start!!
The notify thread is running!!
The notify thread is running!!
The notify thread is running!!
The notify thread is running!!
The notify thread is running!!
The notify thread is stop!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is running!!
The wait thread is stop!!

从运行结果可以看出,并非说产生唤醒动作后,原先处于等待状态的某个线程就能马上继续往下执行同步代码。而是在产生唤醒动作的线程已经执行完所有同步代码的内容后跳出锁(monitorexit)后,原先处于等待的线程才能去重新获取锁并且执行。

2、notifyAll()
其实和notify()作用差不多,只不过notifyAll()会唤醒该对象的等待集中的所有线程,当调用notifyAll()的线程的同步代码执行完成后,被唤醒的所有线程会去竞争锁资源,但最终只能有一个线程能够正常执行。

public class WaitNotifyAll {

    public static void main(String[] args) {
        Object o = new Object();
        WaitNotifyAllThread t1 = new WaitNotifyAllThread(o);
        WaitNotifyAllThread t2 = new WaitNotifyAllThread(o);
        WaitNotifyAllThread t3 = new WaitNotifyAllThread(o);
        WaitNotifyAllThread t4 = new WaitNotifyAllThread(o);
        System.out.println("Application is start!");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (o) {
            o.notifyAll();
        }
    }
}

class WaitNotifyAllThread extends Thread{

    private Object object;

    public WaitNotifyAllThread(Object object) {
        this.object = object;
    }

    @Override
    public void run() {
        synchronized (object) {
            System.out.println(currentThread().getName() + " thread is start!!");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Integer index = 2;
            while (index -- > 0) {
                System.out.println(currentThread().getName() + " is running!!");
            }
            System.out.println(currentThread().getName() + " is stop!!");
            object.notifyAll();
        }
    }
}

输出结果:

Application is start!
Thread-0 thread is start!!
Thread-3 thread is start!!
Thread-2 thread is start!!
Thread-1 thread is start!!
Thread-1 is running!!
Thread-1 is running!!
Thread-1 is stop!!
Thread-2 is running!!
Thread-2 is running!!
Thread-2 is stop!!
Thread-3 is running!!
Thread-3 is running!!
Thread-3 is stop!!
Thread-0 is running!!
Thread-0 is running!!
Thread-0 is stop!!

可见调用并非有序的,而是需要所有原先处于等待集中的线程去竞争锁资源,当它竞争到了,则就进入运行状态,而没有争夺到锁的,则依旧等待。

关于sleep 方法

sleep()方法会根据指定的时间使线程休眠一段时间,但是它和wait()存在的区别就是,wait()会释放出锁,而sleep()会牢牢将锁继续掌握在手里,当睡醒了后就继续往下干活。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值