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()方法,才能唤醒。这节解释了,那么些的优点是和自己推测的是一致的,样线程具有针对想的去唤醒,但是能不能得到锁的这种优先级,那就是另外一回事情了。

原文地址:https://www.cnblogs.com/laj12347/p/4408622.html