源无极

导航

 

一、Condition的使用

       ReentrantLock可以实现等待通知模式,但是需要借助Condition 对象
,使用Condition有更好的灵活性,比如实现多路通知功能也就是在一个Lock
对象里面可以创建多个Condition(对象监视器)实例,线程对象可以注册
在指定的Condition中,从而可以选择性的进行线程通知,在调度线程上更加灵活
在使用wait ,totify进行通知时,被通知的线程由JVM随机选择的。
Synchronized 就相当于整个Lock对象中只有一个Condition对象,所有线程
都注册在它一个对象的身上。线程notifyAll时,没有效率,
需要通知所有的waiting线程,这会出现相当大的效率问题。
package com.it.po.thread11;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service3  {
private ReentrantLock lock =new ReentrantLock();
private Condition condition=lock.newCondition();
public void methodA(){
    try {
        System.out.println("condition begin...");
        condition.await();
        System.out.println("condition end...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

 

package com.it.po.thread11;
public class MyThread3 extends Thread {
private Service3 service3;
    public MyThread3(Service3 service3) {
        this.service3 = service3;
    }
    @Override
    public void run() {
        super.run();
        service3.methodA();
    }
}
package com.it.po.thread11;
import com.it.po.thread07.MyService3;
public class Run3 {
    public static void main(String[] args) throws InterruptedException {
        Service3 myService = new Service3();
        MyThread3 my1 = new MyThread3(myService);
        my1.start();
    }

}

 

condition begin...
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 com.it.po.thread11.Service3.methodA(Service3.java:14)
    at com.it.po.thread11.MyThread3.run(MyThread3.java:10)

 

缺乏监视器。
package com.it.po.thread11;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service3  {
private ReentrantLock lock =new ReentrantLock();
private Condition condition=lock.newCondition();
public void methodA(){
    try {
        lock.lock();
        System.out.println("condition begin...");
        condition.await();
        System.out.println("condition end...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        lock.unlock();
    }
}

}

 

condition begin...

 

二、Condition实现等待、通知。
package com.it.po.thread11;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service4 {
private ReentrantLock lock =new ReentrantLock();
private Condition condition=lock.newCondition();
public void methodA(){
    try {
        lock.lock();
        System.out.println("methodA begin time= "+System.currentTimeMillis());
        condition.await();
        System.out.println("methodA end  time= "+System.currentTimeMillis());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        lock.unlock();
        System.out.println("methodA 释放锁了。。。");
    }
}
    public void methodB(){
        try {
            lock.lock();
            System.out.println("methodB begin time= "+System.currentTimeMillis());
            condition.signal();
            System.out.println("methodB end  time= "+System.currentTimeMillis());
        }finally {
            lock.unlock();
            System.out.println("methodB 释放锁了。。。");
        }
    }

}

 

package com.it.po.thread11;
public class MyThread4 extends Thread {
private Service4 service4;
    public MyThread4(Service4 service4) {
        this.service4 = service4;
    }
    @Override
    public void run() {
        super.run();
        service4.methodA();
    }
}
package com.it.po.thread11;
public class Run4 {
    public static void main(String[] args) throws InterruptedException {
        Service4 myService = new Service4();
        MyThread4 my1 = new MyThread4(myService);
        my1.start();
        Thread.sleep(3000);
        myService.methodB();
    }

}

 

methodA begin time= 1575556005791
methodB begin time= 1575556008790
methodB end  time= 1575556008790
methodB 释放锁了。。。
methodA end  time= 1575556008790
methodA 释放锁了。。。

 

实现等待、通知
总结:
1)Object 的wait() 相当于Condition的await()
2) Object 的wait(long timeOut) 相当于Condition的 await(long time, TimeUnit unit)
3) Object 的notify相当于Contition的signal()
4) Object 的notifyAll相当于Contition的signalAll()
三、使用多个Condition实现等待、通知。
(一)错误的使用方式

package com.it.po.thread11;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service5 {
private ReentrantLock lock =new ReentrantLock();
private Condition condition=lock.newCondition();
public void methodA(){
    try {
        lock.lock();
        System.out.println("methodA begin time= "+System.currentTimeMillis());
        condition.await();
        System.out.println("methodA end  time= "+System.currentTimeMillis());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        lock.unlock();
        System.out.println("methodA 释放锁了。。。");
    }
}
    public void methodB(){
        try {
            lock.lock();
            System.out.println("methodB begin time= "+System.currentTimeMillis());
            condition.await();
            System.out.println("methodB end  time= "+System.currentTimeMillis());
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("methodB 释放锁了。。。");
        }
    }
    public void methodC(){
        try {
            lock.lock();
            System.out.println("methodC begin time= "+System.currentTimeMillis());
            condition.signal();
            Thread.sleep(1000);
            System.out.println("methodC end  time= "+System.currentTimeMillis());
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("methodC 释放锁了。。。");
        }
    }

}

 

 

 

package com.it.po.thread11;
import com.it.po.thread10.MyThread5;
public class Run5 {
    public static void main(String[] args) throws InterruptedException {
        Service5 myService = new Service5();
        MyThread5_1 my1 = new MyThread5_1(myService);
        MyThread5_2 my2 = new MyThread5_2(myService);
        my1.start();
        my2.start();
        Thread.sleep(2000);
        myService.methodC();
    }

}

 

 

 

methodA begin time= 1575557073312
methodB begin time= 1575557073315
methodC begin time= 1575557075312
methodC end  time= 1575557076312
methodC 释放锁了。。。
methodA end  time= 1575557076312
methodA 释放锁了。。。

 

B线程继续等。。。
(二)错误的使用方式
package com.it.po.thread11;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service5 {
private ReentrantLock lock =new ReentrantLock();
private Condition condition=lock.newCondition();
public void methodA(){
    try {
        lock.lock();
        System.out.println("methodA begin time= "+System.currentTimeMillis());
        condition.await();
        System.out.println("methodA end  time= "+System.currentTimeMillis());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        lock.unlock();
        System.out.println("methodA 释放锁了。。。");
    }
}
    public void methodB(){
        try {
            lock.lock();
            System.out.println("methodB begin time= "+System.currentTimeMillis());
            condition.await();
            System.out.println("methodB end  time= "+System.currentTimeMillis());
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("methodB 释放锁了。。。");
        }
    }
    public void methodC(){
        try {
            lock.lock();
            System.out.println("methodC begin time= "+System.currentTimeMillis());
            condition.signalAll();
            Thread.sleep(1000);
            System.out.println("methodC end  time= "+System.currentTimeMillis());
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("methodC 释放锁了。。。");
        }
    }

}

 

methodB begin time= 1575557358266
methodA begin time= 1575557358268
methodC begin time= 1575557360265
methodC end  time= 1575557361265
methodC 释放锁了。。。
methodB end  time= 1575557361265
methodB 释放锁了。。。
methodA end  time= 1575557361265
methodA 释放锁了。。。

 

    ok全部释放锁了,如果想单独唤醒一部分的线程怎么办呢?
这就有必要创建多个Condition了,就是Contition对象
可以唤醒部分线程,有助于提高程序的运行效率,可以先对线程
进行分组,再唤醒指定的组中的线程。

(三)使用多个Condition的正确的使用方式
package com.it.po.thread11;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Service6 {
private ReentrantLock lock =new ReentrantLock();
private Condition condition1=lock.newCondition();
private Condition condition2=lock.newCondition();
public void methodA(){
    try {
        lock.lock();
        System.out.println("methodA begin time= "+System.currentTimeMillis());
        condition1.await();
        System.out.println("methodA end  time= "+System.currentTimeMillis());
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally {
        lock.unlock();
        System.out.println("methodA 释放锁了。。。");
    }
}
    public void methodB(){
        try {
            lock.lock();
            System.out.println("methodB begin time= "+System.currentTimeMillis());
            condition1.await();
            System.out.println("methodB end  time= "+System.currentTimeMillis());
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("methodB 释放锁了。。。");
        }
    }
    public void methodC(){
        try {
            lock.lock();
            System.out.println("methodC begin time= "+System.currentTimeMillis());
            condition2.await();
            System.out.println("methodC end  time= "+System.currentTimeMillis());
        }catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
            System.out.println("methodC 释放锁了。。。");
        }
    }
    public void methodD(){
        try {
            lock.lock();
            System.out.println("methodD begin time= "+System.currentTimeMillis());
            condition1.signalAll();
            System.out.println("methodD end  time= "+System.currentTimeMillis());
        } finally {
            lock.unlock();
            System.out.println("methodD 释放锁了。。。");
        }
    }

}

 

 

 

package com.it.po.thread11;
public class Run6 {
    public static void main(String[] args) throws InterruptedException {
        Service6 myService = new Service6();
        MyThread6_1 my1 = new MyThread6_1(myService);
        MyThread6_2 my2 = new MyThread6_2(myService);
        MyThread6_3 my3 = new MyThread6_3(myService);
        my1.start();
        my2.start();
        my3.start();
        Thread.sleep(2000);
        myService.methodD();
    }

}

 

methodA begin time= 1575557916439
methodC begin time= 1575557916439
methodB begin time= 1575557916440
methodD begin time= 1575557918439
methodD end  time= 1575557918439
methodD 释放锁了。。。
methodA end  time= 1575557918439
methodA 释放锁了。。。
methodB end  time= 1575557918439
methodB 释放锁了。。。

 

线程AB是被Condition1锁住的,可以释放。

由此达到了唤醒指定线程的作用。





posted on 2019-12-05 23:07  源无极  阅读(1120)  评论(0)    收藏  举报