锁,这里讲的就是同步锁,同步执行的锁,释放完之后“锁”之后就丧失了执行能力了,直到notify通知到wait方法,
(notify并不是释放锁),只是通知wait可以去竞争锁了,wait并不是立刻得到锁,锁在别人手里,等待别人释放。
为什么要用这个 ?
线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作。
想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处理?一个办法就是,B线程while(i == 10000),这样两个线程之间就有了通信,B线程不断通过轮训来检测i == 10000这个条件。
这样可以实现我们的需求,但是也带来了问题:CPU把资源浪费了B线程的轮询操作上,因为while操作并不释放CPU资源,导致了CPU会一直在这个线程中做判断操作。如果可以把这些轮询的时间释放出来,给别的线程用,就好了。
结论:而wait是进入线程等待池中等待,让出系统资源。
wait()方法可以使调用该线程的方法释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。
notify()方法可以随机唤醒等待队列中等待同一共享资源的一个线程,并使得该线程退出等待状态,进入可运行状态
notifyAll()方法可以使所有正在等待队列中等待同一共享资源的全部线程从等待状态退出,进入可运行状态
简单地理解就是
wait 就是等待唤醒程序
notify 是唤醒程序
代码示例:
public class JobRun_wait_1 extends Thread {
private Object o;
public JobRun_wait_1(Object o) {
this.o=o;
}
@Override
public void run() {
JobRun_notify_Function jobRun_notify_function=new JobRun_notify_Function();
jobRun_notify_function.wait(o);
}
}
public class JobRun_notify_2 extends Thread {
private Object o;
public JobRun_notify_2(Object o) {
this.o=o;
}
@Override
public void run() {
JobRun_notify_Function jobRun_notify_function=new JobRun_notify_Function();
jobRun_notify_function.notify(o);
}
}
*/
public class JobRun_notify_Function {
//等待唤醒
public void wait(Object o){
synchronized (o){
try {
System.out.println("wait--"+Thread.currentThread().getName()+"--start" );
o.wait();
System.out.println("wait--"+Thread.currentThread().getName()+"--end" );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//唤醒 通知
public void notify(Object o){
try{
synchronized (o){
System.out.println("notify--"+Thread.currentThread().getName()+"--start" );
o.notify();
System.out.println("notify--"+Thread.currentThread().getName()+"--end" );
}
}catch (Exception e){
e.printStackTrace();
}
}
//唤醒 通知
public void notifyAll(Object o){
try{
synchronized (o){
System.out.println("notifyAll--"+Thread.currentThread().getName()+"--start" );
o.notifyAll();
System.out.println("notifyAll--"+Thread.currentThread().getName()+"--end" );
}
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args){
Object o=new Object();
JobRun_wait_1 jobRun_wait=new JobRun_wait_1(o);
jobRun_wait.start();
JobRun_notify_2 jobRun_notify=new JobRun_notify_2(o);
jobRun_notify.start();
}
结果:
wait–Thread-0–start
notify–Thread-1–start
notify–Thread-1–end
wait–Thread-0–end
总结:可以看到,知道notify唤醒后才去执行线程0的结束方法
详细举例可以参考下这个:
https://blog.csdn.net/azhegps/article/details/63031562
代码示例:
public static void main(String[] args) {
Object o = new Object();
JobRun_wait_1 jobRun_wait = new JobRun_wait_1(o);
JobRun_wait_1 jobRun_wait1 = new JobRun_wait_1(o);
JobRun_wait_1 jobRun_wait2 = new JobRun_wait_1(o);
jobRun_wait.start();
jobRun_wait1.start();
jobRun_wait2.start();
JobRun_notify_2 jobRun_notify = new JobRun_notify_2(o);
jobRun_notify.start();
}
结果:
wait–Thread-1–start
notify–Thread-3–start
notify–Thread-3–end
wait–Thread-1–end
wait–Thread-0–start
wait–Thread-2–start
总结:如果有多个wait,再使用notify唤醒,notify只会随机唤醒一个从上图可以得出实际上是第一个执行的会被唤醒
代码示例:
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
JobRun_wait_1 jobRun_wait = new JobRun_wait_1(o);
jobRun_wait.start();
Thread.sleep(3000);
jobRun_wait.interrupt();
}
结果:
wait–Thread-0–start
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at dome_thread.wait_notify.JobRun_notify_Function.wait(JobRun_notify_Function.java:14)
at dome_thread.wait_notify.JobRun_notify_1.run(JobRun_notify_1.java:16)
总结:interrupt能中断等待唤醒的线程,之前也有提到过interrunpt只是给线程做通知。
利用Object对象的notifyAll()方法可以唤醒处于同一监视器下的所有处于wait的线程,举个例子证明一下:
至于唤醒的顺序,就和线程启动的顺序一样,是虚拟机随机的。
代码示例:
public class JobRun_notify_3 extends Thread {
private Object o;
public JobRun_notify_3(Object o) {
this.o = o;
}
@Override
public void run(){
JobRun_notify_Function jnf=new JobRun_notify_Function();
jnf.notifyAll(o);
}
}
public static void main(String[] args) throws InterruptedException {
Object o = new Object();
JobRun_wait_1 jobRun_wait = new JobRun_wait_1(o);
JobRun_wait_1 jobRun_wait1 = new JobRun_wait_1(o);
jobRun_wait.start();
jobRun_wait1.start();
Thread.sleep(1000); //保证wait都执行完后才去调用notify。
JobRun_notify_3 jobRun_notifyAll = new JobRun_notify_3(o);
jobRun_notifyAll.start();
}
结果:
wait–Thread-0–start
wait–Thread-1–start
notifyAll–Thread-2–start
notifyAll–Thread-2–end
wait–Thread-1–end
wait–Thread-0–end
总结:notifyAll可以唤醒所有wait,但是必须都wait所有的线程都在运行状态。
join()方法的作用是等待线程销毁。join()方法反应的是一个很现实的问题,
比如main线程的执行时间是1s,子线程的执行时间是10s,但是主线程依赖子线程执行完的结果,这时怎么办?
可以像生产者/消费者模型一样,搞一个缓冲区,子线程执行完把数据放在缓冲区中,通知main线程,main线程去拿,这样就不会浪费main线程的时间了。另外一种方法,就是join()了。
代码示例:
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--start" );
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--end" );
}
public static void main(String[] args) throws InterruptedException {
JobRun jr=new JobRun();
jr.start();
jr.join();
jr.interrupted();
System.out.println("job已经执行完成了");
}
结果:
Thread-0–start
Thread-0–end
job已经执行完成了
总结:主线程等了4秒钟才去执行,这是接收到了子线程的通知了;很像wait,都是需要别人通知,但是wait,需要notiry通知,join是线程子线程销毁时获得通知。
5、join的实现
join()方法的一个重点是要区分出和sleep()方法的区别。join(2000)也是可以的,表示调用join()方法所在的线程最多等待2000ms,两者的区别在于:
sleep(2000)不释放锁,join(2000)释放锁,因为join()方法内部使用的是wait(),因此会释放锁。看一下join(2000)的源码就知道了,join()其实和join(2000)一样,无非是join(0)而已:
代码示例:
public final void join() throws InterruptedException {
join(0);
}
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;
}
}
}
既然调用join是被wait了,至于怎么被notify的自行找资料 此处待更新…。