Conditon用法整理

       关键字syncronized与wait()和notify()和notifyAll()可以实现等待通知,类ReentrantLock也可以实现同样的功能,但需要借助于Condition,这个类可以实现多路通知,也就是说在一个Lock对象里可以创建多个Condition实例(对象监视器),线程对象可以注册在指定的Condition中,从而可以选择性的通知线程在线程调度上更加灵活。

       而syncronized就相等于整个Lock对象中只有单一的一个Condition对象,所有的线程都注册在它一个上面,线程开始notifyAll()时,需要通知所有的WAITING线程,没有选择权,就会出现资源浪费。下面一个Demo演示的是Condition的错误用法。

public class Demo1 {

    private Lock lock = new ReentrantLock ();
    private Condition condition = lock.newCondition ();

    public void await(){
        try {
            condition.await ();
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1 ();
        new Thread (() -> {
            demo1.await ();
        }).start ();

    }

}

运行后报错:因为在调用Condition.awiat()或single()方法之前需要调用lock.lock()获得同步监视器,切记,跟我们在使用wait方法是同时需要使用synctonized关键字一样一个道理

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036)
	at Lock.KodyLockTest.ConditionStudy.Demo1.await(Demo1.java:19)
	at Lock.KodyLockTest.ConditionStudy.Demo1.lambda$main$0(Demo1.java:28)
	at java.lang.Thread.run(Thread.java:748)

双线程通信案例

public class Demo1 {

    private Lock lock = new ReentrantLock ();
    private Condition condition = lock.newCondition ();

    public void await(){
        try {
            lock.lock ();
            System.out.println (Thread.currentThread ().getName () + "线程获得锁");
            condition.await ();
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }finally {
            System.out.println (Thread.currentThread ().getName () + "线程释放锁");
            lock.unlock ();
        }
    }

    public void single(){
        lock.lock ();
        System.out.println (Thread.currentThread ().getName () + "线程获得锁");
        condition.signal ();
        System.out.println (Thread.currentThread ().getName () + "线程唤醒睡眠线程");
        lock.unlock ();
        System.out.println (Thread.currentThread ().getName () + "线程释放锁");
    }

    public static void main(String[] args) throws InterruptedException{
        Demo1 demo1 = new Demo1 ();
        new Thread (() -> {
            demo1.await ();
        }).start ();
        TimeUnit.SECONDS.sleep (3);

        new Thread (() -> {
            demo1.single ();
        }).start ();

    }

}

控制台信息:首先线程0获得锁后进入等待(意味着放弃了lock对象锁),而后被线程1抢得,线程1接下来唤醒了等待池中等待的线程,此处值得是注册在condition上的线程,目前就只有一个线程0,所以会被唤醒,由于唤醒了线程0但是唤醒了你要继续执行线程0的run代码需要再次获得lock对象锁,这就得看线程1释放没释放了,释放了的话线程0继续抢锁,抢到的话执行完run代码最后也释放。这里需要记住的一点就是线程1唤醒线程0并不能立即执行run代码,因为你需要再次抢锁切记,需要拿到锁才能被唤醒。

Thread-0线程获得锁
Thread-1线程获得锁
Thread-1线程唤醒睡眠线程
Thread-1线程释放锁
Thread-0线程释放锁

双线程交替执行

   使用一个Condition对象加一个标识符来实现交替运行

package Lock.KodyLockTest.ConditionStudy;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Heian
 * @time 19/10/13 16:13
 * @description:线程一打印循环打印 我爱你  线程2打印 love
 */
public class Demo2 {

    private static Lock lock = new ReentrantLock ();
    private static Condition condition = lock.newCondition ();
    //设置一个标识符,如果某个线程打印了则修改标识符位,让自身处于等待,同理另一个线程可以打印
    private static Boolean flag = false;//因为用了线程同步,所以该字面修改是线程可见的

    public static void main(String[] args) {

        new Thread (() -> {
            lock.lock ();
            for (int i=0;i<100;i++){
                try {
                    while (flag == true){
                        condition.await ();
                    }
                    System.out.println ("我爱你");
                    TimeUnit.SECONDS.sleep (1);
                    flag = true;
                    condition.signal ();
                }catch (InterruptedException e){
                    e.printStackTrace ();
                }
            }
            lock.unlock ();
        }).start ();


        new Thread (() -> {
            lock.lock ();
            for (int i=0;i<100;i++){
                try {
                    while (flag == false){
                        condition.await ();
                    }
                    System.out.println ("love");
                    TimeUnit.SECONDS.sleep (1);
                    flag = false;
                    condition.signal ();
                }catch (InterruptedException e){
                    e.printStackTrace ();
                }
            }
            lock.unlock ();
        }).start ();
    }

}

    使用两个Condition对象实现,因为要结束线程声明周期,所以加了个!=10的判断,直接释放锁,而不是还让线程处于等待

package Lock.KodyLockTest.ConditionStudy;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Heian
 * @time 19/10/13 16:13
 * @description:线程一打印循环打印 我爱你  线程2打印 love
 */
public class Demo3 {

    private static Lock lock = new ReentrantLock ();
    private static Condition conditionA = lock.newCondition ();
    private static Condition conditionB = lock.newCondition ();
    private static AtomicInteger atomicIntegerA = new AtomicInteger (0);
    private static AtomicInteger atomicIntegerB = new AtomicInteger (0);

    public static void main(String[] args) {

        new Thread (() -> {
            lock.lock ();
            for (int i=0;i<10;i++){
                try {
                    TimeUnit.SECONDS.sleep (1);
                    System.out.println ("我爱你");
                    conditionB.signal ();//在进入等待池之前先唤醒B,此时A的锁并没有释放
                    if ( atomicIntegerA.incrementAndGet () != 10){
                        conditionA.await ();//如果不是最后一个需要你睡眠,是最后一次的话就直接unlock
                    }
                }catch (InterruptedException e){
                    e.printStackTrace ();
                }
            }
            lock.unlock ();
        }).start ();


        new Thread (() -> {
            lock.lock ();
            for (int i=0;i<10;i++){
                try {
                    TimeUnit.SECONDS.sleep (1);
                    System.out.println ("love");
                    conditionA.signal ();//在进入等待池之前先唤醒A,此时B的锁并没有释放
                    if ( atomicIntegerB.incrementAndGet () != 10){
                        conditionB.await ();
                    }
                }catch (InterruptedException e){
                    e.printStackTrace ();
                }
            }
            lock.unlock ();
        }).start ();

    }

}

三个及以上线程交替执行与顺序执行

       交替执行案例可以参考我的:多线程面试题整合-CSDN博客 案例7  这里我没做线程结束判断,自己手动加下就行,那顺序执行也是一样的。

   这里随机运行三个线程,通过变量num去指定那个线程顺序执行:三个线程随机启动,假设B先启动,B会处于阻塞,假设然后C启动,C也会处于阻塞,当运行到A启动时,会唤醒B,B执行完唤醒C,以此达到ABC顺序运行。

package Lock.KodyLockTest.ConditionStudy;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Heian
 * @time 19/10/13 16:13
 * @description: 线程顺序执行
 */
public class Demo4 {

    private static Lock lock = new ReentrantLock ();
    private static Condition conditionA = lock.newCondition ();
    private static Condition conditionB = lock.newCondition ();
    private static Condition conditionC = lock.newCondition ();
    private static int num = 1;

    public static void main(String[] args) {

        Thread threadA = new Thread (() -> {
            try {
                lock.lock ();
                while (num != 1) {
                    conditionA.await ();
                }
                System.out.println ("我爱你1");
                num = 2;//事情做完了,就赋值为2
                conditionB.signal ();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            } finally {
                lock.unlock ();
            }
        });

        Thread threadB = new Thread (() -> {
            try {
                lock.lock ();
                while (num != 2) {
                    conditionB.await ();
                }
                System.out.println ("我爱你2");
                num = 3;
                conditionC.signal ();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            } finally {
                lock.unlock ();
            }
        });

        Thread threadC = new Thread (() -> {
            try {
                lock.lock ();
                while (num != 3) {
                    conditionC.await ();
                }
                System.out.println ("我爱你3");
                num = 3;
                conditionA.signal ();
            } catch (InterruptedException e) {
                e.printStackTrace ();
            } finally {
                lock.unlock ();
            }
        });
        threadB.start ();
        threadA.start ();
        threadC.start ();

    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值