欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JUC——线程同步锁(Condition精准控制)

程序员文章站 2022-04-28 08:29:10
在进行锁处理的时候还有一个接口:Condition,这个接口可以由用户来自己进行锁的对象创建。 Condition的作用是对锁进行更精确的控制。 Condition的await()方法相当于Object的wait()方法,Condition的signal()方法相当于Object的notify()方 ......

  在进行锁处理的时候还有一个接口:Condition,这个接口可以由用户来自己进行锁的对象创建。

  Condition的作用是对锁进行更精确的控制。

  Conditionawait()方法相当于Objectwait()方法,Conditionsignal()方法相当于Objectnotify()方法,ConditionsignalAll()方法相当于ObjectnotifyAll()方法。

  不同的是Objectwait(), notify(), notifyAll() 方法是和“同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与“互斥锁/共享锁”捆绑使用。

  Object Condition
休眠 wait() await()
唤醒单个线程 notify() signal()
唤醒多个线程 notifyAll() signalAll()

 

 

 

 

JUC——线程同步锁(Condition精准控制)

范例:观察Condition的基本使用

package so.strong.mall.concurrent;

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

public class ConditionDemo {
    private static String msg = null; //设置一个字符串
    public static void main(String[] args)  throws Exception{
        final Lock myLock = new ReentrantLock(); //实例化Lock接口对象
        final Condition condition = myLock.newCondition(); //创建一个新的Condition接口对象
        myLock.lock();
        //如果现在不进行锁定,那么Condition无法执行等代理处理机制,会出现IllegalMonitorStateException
        try {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    myLock.lock();
                    try {
                        msg = "itermis.com";
                        condition.signal(); //唤醒等待的Condition
                    } finally {
                        myLock.unlock();
                    }
                }
            }).start();
            condition.await(); //线程等待
            System.out.println("*******主线程执行完毕,msg="+msg);
        } finally {
            myLock.unlock(); //解除阻塞状态
        }
    }
}
//*******主线程执行完毕,msg=itermis.com

  与之前的Object相比,唯一的区别在于:现在看不见明确的synchronized关键字,而取代synchronizedLock接口中的lock(),unlock()两个方法,而后在阻塞状态(同步状态)下可以使用Condition中的await()signal()方法进行等待与唤醒的操作处理。

 

JUC——线程同步锁(Condition精准控制)

范例:实现数据的缓冲控制

package so.strong.mall.concurrent;

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

/**
 * @author Termis
 * @date 2018/5/3
 */
public class DataBufferDemo {
    public static void main(String[] args) {
        final DataBuffer db = new DataBuffer();
        for (int i = 0; i < 3; i++) { //创建3个写线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 2; j++) {
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        db.put(Thread.currentThread().getName() + "写入数据,j=" + j);
                    }
                }
            }, "生产者-" + i).start();
        }

        for (int i = 0; i < 5; i++) { //创建5个读线程
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            TimeUnit.SECONDS.sleep(3);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        System.out.println("[(" + Thread.currentThread().getName() + ")CONSUMER]" + db.get());
                    }
                }
            }, "消费者-" + i).start();
        }
    }
}

class DataBuffer { //进行数据的缓冲操作控制
    private static final int MAX_LENGTH = 5; // 该类之中保存的数组长度的个数为5
    private Object[] data = new Object[MAX_LENGTH]; //定义一个数组进行全部数据的保存控制
    private Lock myLock = new ReentrantLock(); //创建数据锁
    private Condition putCondition = myLock.newCondition(); //数据保存的Condition控制
    private Condition getCondition = myLock.newCondition(); //数据读取的Condition控制
    private int putIndex = 0; //写入数据的索引
    private int getIndex = 0; //读取数据的索引
    private int count = 0; //当前保存的元素个数

    public Object get() {
        Object getObj = null;
        this.myLock.lock();
        try {
            if (this.count == 0) //没有写入
                this.getCondition.await(); //读取的线程要进行等待
            getObj = this.data[this.getIndex++]; //读取指定索引数据
            if (this.getIndex == MAX_LENGTH)
                this.getIndex = 0; //重新开始读
            this.count--; //因为读了一个数据之后,现在需要减少个数
            this.putCondition.signal(); //告诉写线程可以写入
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.myLock.unlock();
        }
        return getObj;
    }

    public void put(Object obj) { //进行缓冲数据的写入操作
        this.myLock.lock(); //进入独占锁状态
        try {
            if (this.count == MAX_LENGTH)  //保存的数据已经满了
                this.putCondition.await(); //暂时先别进行数据保存了
            this.data[this.putIndex++] = obj; //保存当前数据
            if (this.putIndex == MAX_LENGTH) //现在索引已经写满
                this.putIndex = 0; //重置数组操作的索引脚标
            this.count++; //保存的个数需要做一个追加
            this.getCondition.signal(); //唤醒消费线程
            System.out.println("[(" + Thread.currentThread().getName() + ")写入缓冲-put()]" + obj);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.myLock.unlock(); //不管如何最终一定要进行解锁
        }
    }
}
[(生产者-2)写入缓冲-put()]生产者-2写入数据,j=0
[(生产者-1)写入缓冲-put()]生产者-1写入数据,j=0
[(生产者-0)写入缓冲-put()]生产者-0写入数据,j=0
[(生产者-1)写入缓冲-put()]生产者-1写入数据,j=1
[(生产者-2)写入缓冲-put()]生产者-2写入数据,j=1
[(消费者-3)CONSUMER]生产者-2写入数据,j=0
[(消费者-4)CONSUMER]生产者-1写入数据,j=1
[(消费者-1)CONSUMER]生产者-0写入数据,j=0
[(消费者-2)CONSUMER]生产者-1写入数据,j=0
[(生产者-0)写入缓冲-put()]生产者-0写入数据,j=1
[(消费者-0)CONSUMER]生产者-2写入数据,j=1
[(消费者-3)CONSUMER]生产者-0写入数据,j=1

  对于生产者和消费者模型的实现,除了多线程基础实现之外,也可以采用以上的模式利用LockCondition进行精确控制。