zoukankan      html  css  js  c++  java
  • 3个线程彼此通知

     Condition.await()

       await() 方法  造成当前线程在接到信号或被中断之前一直处于等待状态,并锁释放。

    package threads;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 子线程循环10次,接着主线程循环100次,接着又回到子线程循环 10次,接着在回到主线程又循环100次,如此循环20次
     */
    public class ThreadTest {
    
        public static void main(String[] args) {
    
            final Busess bs = new Busess();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i < 21; i++) {
                        bs.sub2(i);
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i < 21; i++) {
                        bs.sub3(i);
                    }
                }
            }).start();
    
            for (int i = 1; i < 21; i++) {
                bs.main(i);
            }
        }
    
    }
    
    class Busess {
        Lock lock = new ReentrantLock();// crtl alt /
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
        Condition condition3 = lock.newCondition();
    
        private int shouldSub = 1;
    
        public void sub2(int i) {
            lock.lock();
            try {
                while (shouldSub != 2) {
                    try {
                        condition2.await();
                    } catch (Exception e) {
    
                    }
                }
                for (int j = 0; j < 10; j++) {
                    System.out.println("sub2: " + j);
                }
                shouldSub = 3;
                condition3.signal();
            } finally {
                lock.unlock();
            }
        }
    
        public void sub3(int i) {
    
            lock.lock();
            try {
                while (shouldSub != 3) {
                    try {
                        condition3.await();
                    } catch (Exception e) {
    
                    }
                }
                for (int j = 0; j < 20; j++) {
                    System.out.println("sub3: " + j);
                }
                shouldSub = 1;
                condition1.signal();
            } finally {
                lock.unlock();
            }
        }
    
        public void main(int i) {
            lock.lock();
            try {
                while (shouldSub != 1) {
                    try {
                        condition1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                for (int j = 0; j < 50; j++) {
                    System.out.println("main: " + j);
                }
                shouldSub = 2;
                condition2.signal();
            } finally {
                lock.unlock();
            }
        }
    }

    这个例子出处是张孝祥的视频,但是经过测试使用一个Condition  就可以。

    signal方法:唤醒一个等待线程。 如果所有的线程都在等待此条件,则选择其中的一个唤醒。在从 await 返回之前,该线程必须重新获取锁。

    通过API可以知道,Condition  是选择其中一个唤醒,而不是那个对象调用唤醒那个。

    修改后的代码如下

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 子线程循环10次,接着主线程循环100次,接着又回到子线程循环 10次,接着在回到主线程又循环100次,如此循环50次
     */
    public class ThreadTest {
    
        public static void main(String[] args) {
    
            final Busess bs = new Busess();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i < 21; i++) {
                        bs.sub2(i);
                    }
                }
            }).start();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 1; i < 21; i++) {
                        bs.sub3(i);
                    }
                }
            }).start();
    
            for (int i = 1; i < 21; i++) {
                bs.main(i);
            }
        }
    
    }
    
    class Busess {
        Lock lock = new ReentrantLock();// crtl alt /
        Condition condition = lock.newCondition();
    
        private int shouldSub = 1;
    
        public void sub2(int i) {
            lock.lock();
            try {
                while (shouldSub != 2) {
                    try {
                        condition.await();
                    } catch (Exception e) {
    
                    }
                }
                for (int j = 0; j < 10; j++) {
                    System.out.println("sub2: " + j);
                }
                shouldSub = 3;
                condition.signal();
            } finally {
                lock.unlock();
            }
        }
    
        public void sub3(int i) {
    
            lock.lock();
            try {
                while (shouldSub != 3) {
                    try {
                        condition.await();
                    } catch (Exception e) {
    
                    }
                }
                for (int j = 0; j < 20; j++) {
                    System.out.println("sub3: " + j);
                }
                shouldSub = 1;
                condition.signal();
            } finally {
                lock.unlock();
            }
        }
    
        public void main(int i) {
            lock.lock();
            try {
                while (shouldSub != 1) {
                    try {
                        condition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                for (int j = 0; j < 50; j++) {
                    System.out.println("main: " + j);
                }
                shouldSub = 2;
                condition.signal();
            } finally {
                lock.unlock();
            }
        }
    }

    java jdk中的一个例子,张孝祥的解释是,这两个condition 是有好处的,但是经过测试,在多个线程的时候,在堆栈满的时候,会彼此传递锁,经过测试,当4take的线程都处于等待状态,2个put的线程也处于等待的状态,take方法走完之后,2个put方法并不一定优先获得锁。 也许这么写的好处就是通知的线程找了,condition只需要通知自己管理的线程,能做到定点通知,二前程是否能优先获得到锁是另外一回事情。

    package con1;
    
    import java.util.Random;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class BoundedBufferTest {
    
        public static void main(String[] args) {
            final BoundedBuffer buffer=new BoundedBuffer();
        
            for (int i = 0; i < 5; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (true) {
                            try {
                                buffer.put(new Random().nextInt(200));
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();;
            }
            
            
            for (int i = 0; i < 5; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        while (true) {
                            try {
                                Object obj=buffer.take();
                                System.out.println(obj.toString());
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }).start();
            }
            System.out.println(11);
        }
        
        
    }
    
    class BoundedBuffer {
        final Lock lock = new ReentrantLock();// 锁对象
        final Condition notFull = lock.newCondition();// 写线程条件
        final Condition notEmpty = lock.newCondition();// 读线程条件
    
        final Object[] items = new Object[100];// 缓存队列
        int putptr/* 写索引 */, takeptr/* 读索引 */, count/* 队列中存在的数据个数 */;
    
        public void put(Object x) throws InterruptedException {
            lock.lock();
            try {
                while (count == items.length)
                    // 如果队列满了
                    notFull.await();// 阻塞写线程
                items[putptr] = x;// 赋值
                if (++putptr == items.length)
                    putptr = 0;// 如果写索引写到队列的最后一个位置了,那么置为0
                ++count;// 个数++
                notEmpty.signal();// 唤醒读线程
            } finally {
                lock.unlock();
            }
        }
    
        public Object take() throws InterruptedException {
            lock.lock();
            try {
                while (count == 0)
                    // 如果队列为空
                    notEmpty.await();// 阻塞读线程
                Object x = items[takeptr];// 取值
                if (++takeptr == items.length)
                    takeptr = 0;// 如果读索引读到队列的最后一个位置了,那么置为0
                --count;// 个数--
                notFull.signal();// 唤醒写线程
                return x;
            } finally {
                lock.unlock();
            }
        }
    }

     因为两个condition是从同一个锁中获得的不同对象,所以他们彼此还是保持互斥的,

    await方法在API中的介绍
    void await()

    造成当前线程在接到信号或被中断之前一直处于等待状态。
    与此 Condition 相关的锁以原子方式释放,并且出于线程调度的目的,将禁用当前线程,且在发生以下四种情况之一 以前,当前线程将一直处于休眠状态:

    • 其他某个线程调用Condition signal() 方法,并且碰巧将当前线程选为被唤醒的线程;
    • 其他某个线程调用此 ConditionsignalAll() 方法;
    • 其他某个线程中断当前线程,且支持中断线程的挂起;
    • 发生“虚假唤醒” 

    在API中也是提到,调用此condition的signal()方法,才能唤醒。这节解释了,那么些的优点是和自己推测的是一致的,样线程具有针对想的去唤醒,但是能不能得到锁的这种优先级,那就是另外一回事情了。

  • 相关阅读:
    今天的雪糕格外好吃!
    定了!对于本周四(7.16日)抽奖活动取消简要说明,新抽奖活动暂定下周三(7.22日)...
    你喜欢什么样的课堂?
    无题
    属于你们的“礼仪小课堂”
    红歌合唱之团结就是力量
    《此生未完成》痛句摘录(一)
    端午前夕的班级小游戏
    排序>插入排序 小强斋
    排序>交换排序 小强斋
  • 原文地址:https://www.cnblogs.com/laj12347/p/4408622.html
Copyright © 2011-2022 走看看