重入锁ReentrantLock+Condition 实现等待/通知

        在Java多线程编程中,可以使用Synchronized来实现同步,可以synchronized类,方法或代码块,另外还可以使用ReentrantLock来实现同样的功能,而且功能更加强大。

        1. 使用ReentrantLock实现同步

public class ReentrantLockTest {

    private Lock lock = new ReentrantLock();

    public void testLock(){

        //获取锁
        lock.lock();
        try {
            for (int i = 0; i < 10; i++){
                System.out.println("Thread - " + Thread.currentThread().getName() + "===" + i);

                    Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 解锁
        lock.unlock();
    }
}
public class ReentrantLockThread extends Thread {

    private ReentrantLockTest reentrantLockTest;

    public ReentrantLockThread(ReentrantLockTest reentrantLockTest){

        super();
        this.reentrantLockTest = reentrantLockTest;
    }

    @Override
    public void run(){

        reentrantLockTest.testLock();
    }
}
public class TestLock {

    public static void main(String[] args){

        ReentrantLockTest reentrantLockTest = new ReentrantLockTest();

        Thread threadA = new ReentrantLockThread(reentrantLockTest);
        threadA.setName("A");
        Thread threadB = new ReentrantLockThread(reentrantLockTest);
        threadB.setName("B");

        threadA.start();
        threadB.start();
    }
}

运行结果

加锁结果:

重入锁ReentrantLock+Condition 实现等待/通知_第1张图片

未加锁结果

重入锁ReentrantLock+Condition 实现等待/通知_第2张图片

从运行结果可以看出,使用了ReentrantLock的lock()方法和unlock()方法后,代码也达到了同步的效果。

接下来继续验证ReentrantLock实现同步是否持有对象锁

继续给添加新的方法X和Y,然后不同的线程调用不同的方法

public class ReentrantLockTest {

    private Lock lock = new ReentrantLock();

    public void testLockX(){
        try {
            //获取锁
            lock.lock();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "====Method X");
            Thread.sleep(1000);
            System.out.println("Thread --- " + Thread.currentThread().getName() + "====Method X");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

    public void testLockY(){
        try {
            //获取锁
            lock.lock();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "====Method Y");
            Thread.sleep(1000);
            System.out.println("Thread --- " + Thread.currentThread().getName() + "====Method Y");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }
}

调用X方法的线程、

public class ReentrantLockThreadX extends Thread {

    private ReentrantLockTest reentrantLockTest;

    public ReentrantLockThreadX(ReentrantLockTest reentrantLockTest){

        super();
        this.reentrantLockTest = reentrantLockTest;
    }

    @Override
    public void run(){

        reentrantLockTest.testLockX();
    }
}

调用Y方法的线程

public class ReentrantLockThreadY extends Thread{

    private ReentrantLockTest reentrantLockTest;

    public ReentrantLockThreadY(ReentrantLockTest reentrantLockTest){

        super();
        this.reentrantLockTest = reentrantLockTest;
    }

    @Override
    public void run(){

        reentrantLockTest.testLockY();
    }
}

测试类

public class TestLock {

    public static void main(String[] args){

        ReentrantLockTest reentrantLockTest = new ReentrantLockTest();

        Thread threadA = new ReentrantLockThreadX(reentrantLockTest);
        threadA.setName("A");
        Thread threadB = new ReentrantLockThreadX(reentrantLockTest);
        threadB.setName("B");

        Thread threadC = new ReentrantLockThreadY(reentrantLockTest);
        threadC.setName("C");
        Thread threadD = new ReentrantLockThreadY(reentrantLockTest);
        threadD.setName("D");

        threadA.start();
        threadB.start();
        threadC.start();
        threadD.start();
    }
}

运行结果

重入锁ReentrantLock+Condition 实现等待/通知_第3张图片

从结果可以看出,ReentrantLock获取的是对象锁,即持有“对象监听器”,当某线程持有了对象锁后,其他的线程只能等待锁释放是争抢锁。线程执行的顺序是随机的。

        2. 使用ReentrantLock和Condition实现等待/通知

Synchronized和wait()+notify()/notifyAll()可以实现等待/通知模式,那么ReentrantLock怎样实现呢?

ReentrantLock可以和Condition对象可以实现等待/通知的效果

下面通过代码看效果

public class LockAndCondition {

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

    public void mockWait(){

        try {
            // 加锁
            lock.lock();
            System.out.println("已经加锁");
            condition.await();
            System.out.println("已经await");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
            System.out.println("已经释放锁");
        }
    }
}
public class TestLockAndCondition {

    public static void main(String[] args){

        LockAndCondition lockAndCondition = new LockAndCondition();
        Thread thread = new LockAndConditionThread(lockAndCondition);
        thread.start();
    }
}
public class LockAndConditionThread extends Thread {

    private LockAndCondition lockAndCondition;

    public LockAndConditionThread(LockAndCondition lockAndCondition){

        super();
        this.lockAndCondition = lockAndCondition;
    }

    @Override
    public void run(){

        lockAndCondition.mockWait();
    }
}

运行结果

重入锁ReentrantLock+Condition 实现等待/通知_第4张图片

从运行的结果我们可以看出,代码执行到“已经加锁”的下面await方法处,线程处于等待状态了没有继续向下执行,接下来我们继续测试唤醒该线程

package thread.reentrantlock;

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

public class LockAndCondition {

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

    public void mockWait(){

        try {
            // 加锁
            lock.lock();
            System.out.println("In mockWait 已经加锁");
            condition.await();
            System.out.println("已经await");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 释放锁
            lock.unlock();
            System.out.println("In mockWait 已经释放锁");
        }
    }

    /**
     * 新加唤醒方法
     */
    public void mockNotify(){

        try {
            // 加锁
            lock.lock();
            System.out.println("In mockNotify 已经加锁");
            condition.signal();
            System.out.println("已经signal");
        } finally {
            // 释放锁
            lock.unlock();
            System.out.println("In mockNotify 已经释放锁");
        }
    }
}

测试类

public class TestLockAndCondition {

    public static void main(String[] args) throws InterruptedException {

        LockAndCondition lockAndCondition = new LockAndCondition();
        Thread thread = new LockAndConditionThread(lockAndCondition);
        thread.start();
        lockAndCondition.mockNotify();
    }
}

运行结果

重入锁ReentrantLock+Condition 实现等待/通知_第5张图片

通过condition的signle()方法唤醒等待线程。

同样的,condition也有方法可以唤醒全部等待线程,使用signalAll()方法,而且,condition有更加强大的用户,就是唤醒指定线程。下面继续测试。

        3. 使用多个condition唤醒指定线程

        首先,定义多个condition

package thread.reentrantlock;

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

public class MoreCondition {

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

    public void testMoreConditionAwaitA(){

        try{
            lock.lock();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "Method --- A --- Lock");
            conditionA.await();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "Method --- A --- 被唤醒");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void testMoreConditionSignalAllA(){

        try {
            lock.lock();
            //唤醒所有使用conditionA等待的线程
            conditionA.signalAll();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "Method --- A --- SignalAll");
        } finally {
            lock.unlock();
        }
    }

    public void testMoreConditionAwaitB(){

        try{
            lock.lock();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "Method --- B --- Lock");
            conditionB.await();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "Method --- B --- 被唤醒");
        } catch (InterruptedException e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void testMoreConditionSignalAllB(){

        try {
            lock.lock();
            conditionB.signalAll();
            System.out.println("Thread --- " + Thread.currentThread().getName() + "Method --- B --- SignalAll");
        } finally {
            lock.unlock();
        }
    }
}

调用A方法的线程

package thread.reentrantlock;

public class MoreConditionThreadA extends Thread{

    private MoreCondition moreCondition;

    public MoreConditionThreadA(MoreCondition moreCondition){

        super();
        this.moreCondition = moreCondition;
    }

    @Override
    public void run(){
        moreCondition.testMoreConditionAwaitA();
    }
}

调用B方法的线程

package thread.reentrantlock;

public class MoreConditionThreadB extends Thread {

    private MoreCondition moreCondition;

    public MoreConditionThreadB(MoreCondition moreCondition){

        super();
        this.moreCondition = moreCondition;
    }

    @Override
    public void run(){

        this.moreCondition.testMoreConditionAwaitB();
    }
}

测试类

package thread.reentrantlock;

public class MoreConditionTest {

    public static void main(String[] args) throws InterruptedException {

        MoreCondition moreCondition = new MoreCondition();

        Thread threadA1 = new MoreConditionThreadA(moreCondition);
        Thread threadA2 = new MoreConditionThreadA(moreCondition);
        Thread threadA3 = new MoreConditionThreadA(moreCondition);
        Thread threadB1 = new MoreConditionThreadB(moreCondition);
        Thread threadB2 = new MoreConditionThreadB(moreCondition);
        Thread threadB3 = new MoreConditionThreadB(moreCondition);

        threadA1.setName("A1");
        threadA2.setName("A2");
        threadA3.setName("A3");
        threadB1.setName("B1");
        threadB2.setName("B2");
        threadB3.setName("B3");

        threadA1.start();
        threadA2.start();
        threadA3.start();

        threadB1.start();
        threadB2.start();
        threadB3.start();

        Thread.sleep(2000);
        // 唤醒A线程
        moreCondition.testMoreConditionSignalAllA();
        // 唤醒B线程
//        moreCondition.testMoreConditionSignalAllB();
    }
}

运行结果

重入锁ReentrantLock+Condition 实现等待/通知_第6张图片

所有调用A方法的线程全部别唤醒,调用B方法的线程依然在等待。

通过这个例子可以看出,使用condition+signal/signalAll方法可以唤醒指定的线程

你可能感兴趣的:(多线程编程)