Lock
ReentrantLock 是我们常用的锁,日常我们都只使用了其中一部分功能如下:
ReentrantLock lock = new ReentrantLock(); lock.lock(); try { .... } finally { lock.unlock(); }
实际上Java提供的LinkedBlockingQueue类就是基于ReentrantLock与Condition结合使用的,这是很经典的生产与消费场景,里面有两个锁putLock与takeLock锁。解决问题:取元素时takeLock已经获取到锁了,但是由于列队是空的,使用notEmpty.await()使当前线程处理等待状态,这时如果有新的线程调用take方法时,新的线程也能获取到锁,也会继续等待,当put元素后, notEmpty.signal()发送信号,会唤醒其中一个等待线程。
使用condition可以使线程交互变的更加灵活,ReentrantLock可以定义公平锁与非公平锁,公平锁可以保证线程访问顺序,非公平锁不一定保证线程访问顺序,默认为非公平锁。
//每次取完之后使用自唤醒方法使其它等待线程,多了一重信息通知,取完之后会调用notFull方法唤醒正在等写入的方法 public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly();//获取锁 try { while (count.get() == 0) {//如果当前元素为0线程等待 notEmpty.await(); } x = dequeue();//取一个元素 c = count.getAndDecrement();//总数减1 if (c > 1)//如果有元素 继续唤醒一个等待线程 notEmpty.signal(); } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; }
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); int c = -1; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); try { while (count.get() == capacity) {//列队满,等列队有空间 notFull.await(); } enqueue(node);//插入元素 c = count.getAndIncrement();//总数加1 if (c + 1 < capacity)//列队未满,唤醒正在等待的线程 notFull.signal(); } finally { putLock.unlock(); } if (c == 0)//通知正在等待取元素的线程 signalNotEmpty(); }
synchronized (writeLock) { while (runThreadNum >= 5) { try { System.out.println("threadNum:" + runThreadNum); writeLock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }
import java.util.Date; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; /** * Created by zengrenyuan on 18/6/11. */ public class TestLock { public static final int maxNum = 1; private final ReentrantLock lock = new ReentrantLock(); private final Condition notFull = lock.newCondition(); private final Condition notEmpty = lock.newCondition(); private AtomicInteger count = new AtomicInteger(0); public static void main(String[] args) throws InterruptedException { final TestLock testLock = new TestLock(); testLock.putThread("线程1"); testLock.putThread("线程2"); testLock.putThread("线程3"); testLock.putThread("线程4"); testLock.putThread("线程5"); testLock.readThread("读线程"); } public void readThread(String name) { Thread thread = new Thread(new Runnable() { @Override public void run() { while (true) { try { read(); } catch (InterruptedException e) { e.printStackTrace(); } } } }); thread.setName(name); thread.start(); } public void read() throws InterruptedException { lock.lock(); try { while (count.get() == 0) { notEmpty.await(); } System.out.println("read:" + count.decrementAndGet()); notFull.signal(); } finally { lock.unlock(); } } public void putThread(String name) { Thread thread = new Thread(new Runnable() { @Override public void run() { try { print(); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.setName(name); thread.start(); } public void print() throws InterruptedException { lock.lock(); try { System.out.println("threadName" + Thread.currentThread().getName()); while (count.get() == maxNum) { notFull.await(); } System.out.println("put:" + count.getAndIncrement() + " threadName" + Thread.currentThread().getName()); System.out.println(MiscUtils.formatDate(new Date(), MiscUtils.STANDARDPATTERN)); notEmpty.signal(); } finally { lock.unlock(); } } }
https://www.jianshu.com/p/eb112b25b848
http://jszx-jxpt.cuit.edu.cn/JavaAPI/java/util/concurrent/locks/Condition.html
http://jszx-jxpt.cuit.edu.cn/JavaAPI/java/util/concurrent/locks/Lock.html
https://www.jianshu.com/p/71ad3c675cbe