JUC——线程同步锁(Condition精准控制)
在进行锁处理的时候还有一个接口:Condition,这个接口可以由用户来自己进行锁的对象创建。
Condition的作用是对锁进行更精确的控制。
Condition的await()方法相当于Object的wait()方法,Condition的signal()方法相当于Object的notify()方法,Condition的signalAll()方法相当于Object的notifyAll()方法。
不同的是Object的wait(), notify(), notifyAll() 方法是和“同步锁”(synchronized关键字)捆绑使用的;而Condition是需要与“互斥锁/共享锁”捆绑使用。
Object | Condition | |
休眠 | wait() | await() |
唤醒单个线程 | notify() | signal() |
唤醒多个线程 | notifyAll() | signalAll() |
范例:观察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关键字,而取代synchronized是Lock接口中的lock(),unlock()两个方法,而后在阻塞状态(同步状态)下可以使用Condition中的await()与signal()方法进行等待与唤醒的操作处理。
范例:实现数据的缓冲控制
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
对于生产者和消费者模型的实现,除了多线程基础实现之外,也可以采用以上的模式利用Lock与Condition进行精确控制。