多线程之线程通信wait和notify的使用

使用wait和notify方法实现线程之间的通信,注意,这两个方法是Object类的方法,也就是说Java为所有的对象都提供的这两个方法。

1 wait和notify必须配合synchronized关键字使用。

2 wait方法释放锁,notify方法不释放锁。

3 还要注意一点 就是涉及到线程之间的通信,就肯定会用到validate修饰。

案例:
t1线程向集合中不断添加元素,当集合中元素个数为5的时候,就向t2线程发出通知,(当集合元素个数不等于5时候,t2线程处于等待状态),然后t2向下执行,抛出异常。

package com.wuk.Demo;

import java.util.ArrayList;
import java.util.List;

/**
 * wait和notify的使用
 * 
 * @author Administrator
 *
 */
public class MyThread004 {


    private static volatile List list=new ArrayList();

    public void add() {

        list.add("wuk");
    }

    public  int size() {

        return list.size();
    }

    public static void main(String[] args) {

        MyThread004 list1=new MyThread004();

        Object obj=new Object();

        Thread t1=new Thread(new Runnable() {

            @Override
            public void run() {

                synchronized (obj) {

                    System.out.println("t1线程启动。。。。");
                    for(int i=0;i<10;i++) {
                        list1.add();
                        System.out.println("当前线程"+Thread.currentThread().getName()+"添加了一个元素");
                        try {
                            Thread.sleep(500);
                            if(list1.size()==5) {
                                System.out.println("已经发出通知。。");
                                obj.notify();
                            }


                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
        },"t1");

        Thread t2=new Thread (new Runnable() {

            @Override
            public void run() {

                synchronized (obj) {

                    System.out.println("t2启动。。。");
                    if(list1.size()!=5) {

                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
                    throw new RuntimeException();
                }
            }
        },"t2");


        t2.start();
        t1.start();
    }
}

打印结果:

t2启动。。。
t1线程启动。。。。
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
已经发出通知。。
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程:t2收到通知线程停止..
Exception in thread "t2" java.lang.RuntimeException
    at com.wuk.Demo.MyThread004$2.run(MyThread004.java:79)
    at java.lang.Thread.run(Unknown Source)

分析:
首先启动t2线程,使得t2线程处于等待状态,然后当集合等于5的时候,t1向t2线程发出通知,但是并不会释放锁,所以当t1执行完毕后,t2线程才会向下执行。

分析几种情况:
(1) 有人说 validate不是可以实现线程之间的可见性吗,那么我就不需要t1通知,当t2发现集合元素是5了就会往下执行?
去掉obj.notify(); 结果是:

t2启动。。。
t1线程启动。。。。
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
已经发出通知。。
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素

分析:
因为当t2执行了wait()方法,就会处于等待状态,如果不去唤醒他,他就会一直等待下去。

(2)如果我们先让t1执行会是什么结果?

t1线程启动。。。。
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
已经发出通知。。
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
当前线程t1添加了一个元素
t2启动。。。

分析:
因为notify不释放锁,如果t1先执行,就会先拥有锁,那么只有等到t1执行完毕以后,t2才会有机会执行,这时候集合长度早都不是5了,所以就会一直等待下去。

猜你喜欢

转载自blog.csdn.net/wu2374633583/article/details/80739676