Java并发中的通知/等待模式实现(2种)

Condition接口实现了通知/等待

方法:await()当前线程进入等待状态,直到被通知(signal或者中断)
awaitUninterruptibly()不能被中断
awaitNanos()可以设置纳秒级别的超时时间
awaitUntil()当前线程进入等待状态直到被通知(可以设置时间)
signal()唤醒
signalAll()唤醒所有

线程调用condition.await()会释放锁,构造成节点加入等待队列并且进入等待状态,从await返回的时候一定是获取了Condition相关的锁,从队列角度看:相当于同步队列的首节点(获取了锁的节点)移动到了Condition的等待队列,进入等待队列的线程必须先要获取锁,因此Condition进入等待队列的操作不用CAS操作来保证线程安全,而使用锁来保证。

话不多说直接上代码:

public class ConditionTest {

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        AAA test = new AAA();
        Thread add = new Thread(new Writer(test), "add");// 设定add比get慢三倍,实验表明get会等待add添加元素才回去获取
        Thread get = new Thread(new Reader(test), "get");
        get.start();
        add.start();
        // TimeUnit.SECONDS.sleep(1);
        add.join();
        get.join();
        add.interrupt();
    }

}

class Writer implements Runnable {
    private AAA a;

    public Writer(AAA a) {
        super();
        this.a = a;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            try {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
                a.add(123);
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

class Reader implements Runnable {
    private AAA b;

    public Reader(AAA b) {
        super();
        this.b = b;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while (true) {
            try {
                b.get();
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

class AAA {
    Lock lock = new ReentrantLock(false);
    Condition notFull = lock.newCondition();
    Condition notEmpty = lock.newCondition();
    static int[] queue = new int[10];
    volatile int count = 0, readIndex = 0, writeIndex = 0;

    public void add(int i) throws InterruptedException {
        lock.lock();
        try {
            while (count == queue.length) {
                notFull.await();//线程会陷入await方法中,同时执行finally,释放锁
            }
            queue[writeIndex] = i;
            if (++writeIndex == queue.length) {
                writeIndex = 0;
            }
            System.out.println("add:count=" + count);
            ++count;
            notEmpty.signal();//会唤醒等待队列中等待时间最长的线程(也就是等待队列的队首线程),并且移入到同步队列

        } finally {
            lock.unlock();
        }
    }

    public int get() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();
            }
            int a = queue[readIndex];
            if (++readIndex == queue.length) {
                readIndex = 0;
            }
            System.out.println("get:count=" + count + ":" + "get=" + a);
            --count;
            notFull.signal();
            return a;
        } finally {
            lock.unlock();
        }
    }
}

synchronized和lock实现通知/等待:

public class SynchronizedTest {
    static Lock lock = new ReentrantLock(true);
    static boolean flag = true;// 值传递,所以在Notify线程修改的时候需要修改Wait线程的成员变量(flag)

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        Thread wait = new Thread(new Wait(flag, lock), "wait Thread");
        Thread notify = new Thread(new Notify(flag, lock), "notify Thread");
        wait.start();
        TimeUnit.SECONDS.sleep(2);
        notify.start();
    }

}

class Wait implements Runnable {
    public static boolean flag;
    private Lock lock;

    public Wait(boolean flag, Lock lock) {
        super();
        this.flag = flag;
        this.lock = lock;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (lock) {
            System.out.println("wait flag:" + flag);
            while (flag) {
                try {
                    System.out.println("still waiting");
                    lock.wait();// 从方法返回,执行下一步
                    System.out.println("do the next");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println("notified! doSomething else");
        }
    }
}

class Notify implements Runnable {
    private boolean flag;
    private Lock lock;

    public Notify(boolean flag, Lock lock) {
        super();
        this.flag = flag;
        this.lock = lock;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        synchronized (lock) {
            lock.notify();// 通知不会释放lock锁,只有当调用notify的线程释放lock锁,另外的线程才能从wait方法返回
            // notify方法只是将线程从等待队列移入同步队列,从wait状态返回的前提是获取调用对象的锁
            Wait.flag = false;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        synchronized (lock) {
            try {
                TimeUnit.SECONDS.sleep(1);
                System.out.println("keep the lock don not let the wait() return");// 继续持有锁,阻止线程从wait方法返回
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

你可能感兴趣的:(java基础,java并发编程)