Lock与Synchronized简介
Synchornized相信大家用的已经比较熟悉了,这里我就不介绍它的用法了
Synchronized被称为同步锁或者是隐式锁,隐式锁与显式锁区别在于,隐式锁的获取和释放都需要出现在一个块结构中,而且是有顺序的,获取锁的顺序和释放锁的顺序必须相反,就是说,最开始获取了A锁,然后获取了B锁,那么释放锁的顺序就是先释放B,在释放A。
随着并发编程应用越来越多,我们有时会遇到一些问题,获取锁和释放锁不在同一代码块,顺序也不确定,这个时候我们可以使用Lock来实现,Lock是一个接口,提供了无条件的、可中断的,可轮询的、定时的锁获取操作,所有的获取锁和释放锁都是显示的,我们来看下jdk中有哪些方法
Condition
condition实现了类似Object中的wiat(),notify(),notifyAll()方法,condition优点在于,可以唤醒某个特定的线程此点可以用在类似于生产者消费者模式中,当生产者往队列中存储数据时,如果队列满了,则调用condition.await(),同时唤醒消费者,当消费者获取队列中的元素时,如果队列为空,则等待,同时唤醒生产者。condition类被绑定在Lock上,condition内部维护了一个队列,队列是单链表实现的
package com.lock;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* condition有类似Object的wait(),notify(),notifyAll()方法,配合Lock使用
* @author lijh
*
*/
public class MyCondition {
public static void main(String[] args){
List<Integer> list = new ArrayList<Integer>(5);
//int [] a = new int[5];
ReentrantLock rt = new ReentrantLock();
Condition producerCondi = rt.newCondition();
Condition consumerCondi = rt.newCondition();
Producer p1 = new Producer(list,producerCondi,consumerCondi,rt);
//Producer p2 = new Producer(list,producerCondi,consumerCondi,rt);
Consumer c1 = new Consumer(list,producerCondi,consumerCondi,rt);
ExecutorService pool = Executors.newFixedThreadPool(3);
pool.execute(p1);
//pool.execute(p2);
pool.execute(c1);
//pool.shutdown();
}
}
/**
* 生产者
* @author lijh
*
*/
class Producer implements Runnable{
private List<Integer> list;
private Lock lock;
private Condition producerCondi;
private Condition consumerCondi;
public Producer(List<Integer> list,Condition producerCondi,Condition consumerCondi,Lock lock){
this.list = list;
this.producerCondi = producerCondi;
this.consumerCondi = consumerCondi;
this.lock = lock;
}
@Override
public void run() {
lock.lock();
while(list.size() < 5){//
Random r = new Random();
int i=0;
list.add(i = r.nextInt(20));
System.out.println("数据"+i+"插入成功!");
}
try {
System.out.println("list已经满了,生产者进入等待状态");
producerCondi.await();
System.out.println("调用await()方法后,什么时候执行这个???");
consumerCondi.signalAll();
System.out.println("Producer");
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
lock.unlock();
}
}
}
class Consumer implements Runnable{
private List<Integer> list;
private Lock lock;
private Condition producerCondi;
private Condition consumerCondi;
public Consumer(List<Integer> list,Condition producerCondi,Condition consumerCondi,Lock lock){
this.list = list;
this.producerCondi = producerCondi;
this.consumerCondi = consumerCondi;
this.lock = lock;
}
@Override
public void run() {
lock.lock();
while(list.size() >0){
System.out.println(list.remove(0));
}
try {
System.out.println("list为空,消费者进入等待状态");
producerCondi.signalAll();
consumerCondi.await();
System.out.println("Consumer");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
尝试理解下Condition.await()的源代码
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();//插入当前节点到condition
long savedState = fullyRelease(node);//释放锁
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);//在被唤醒前,禁用当前线程
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//如果线程被中断退出while
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
//插入一个节点到Condition里面
private Node addConditionWaiter() {
Node t = lastWaiter;//获取在Condition中的最后一个节点
// If lastWaiter is cancelled, clean out. 如果lastWaiter取消了,清理掉此节点看 unlinkCancelledWaiters()
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;//如果链表为空,则把这个新建的节点当做头结点
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
//
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;//获取t节点的下一个节点
if (t.waitStatus != Node.CONDITION) {//如果t已经不再condition中了,则trail节点指向t后面的一个节点
t.nextWaiter = null;//置空t的next指针
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;//获取下一个节点,再次while
}
}
final long fullyRelease(Node node) {
boolean failed = true;
try {
long savedState = getState();//得到当前信号量
if (release(savedState)) {//如果释放成功
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)//如果释放失败
node.waitStatus = Node.CANCELLED;
}
}
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)//如果当前节点在condition上或者当前节点是头结点
return false;
if (node.next != null) // If has successor, it must be on queue
return true;
return findNodeFromTail(node);
}
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;//如果线程没中断,返回0,否则如果线程被中断返回THROW_IE -1,被唤醒后中断REINTERRUPT 1
}
Condition源码就看到这里了,主要是了解链表
ReentrantLock--可重入锁
ReentrantLock特点
1.初始化时,可以指定是公平锁还是非公平锁,通过AQS实现的,公平锁的的意思是(FIFO),先等待的线程先获取锁
2.在ReentrantLock中可以使用Condition类(一个将Object的wait(),notify(),notifyAll()方法分解成不同对象,来配合Lock工作)
3.ReentrantLock提供了可以中断等待锁的机制,就是说一个线程在获取锁的时候,如果这个线程中断了,则不再获取锁
ReentrantLock一些常用的方法
package com.lock;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* 重入锁
* @author lijh
*
*/
public class MyReentrantLock {
public static void main(String[] args) throws InterruptedException {
Worker1 worker1 = new Worker1(1);
Worker1 worker2 = new Worker1(2);
Thread t1 = new Thread(worker1,"t1");
Thread t2 = new Thread(worker2,"t2");
t1.start();
t2.start();
//t1.join();//main线程等待t1线程结束
//t2.join();//main线程等待t2线程结束
TimeUnit.SECONDS.sleep(3);
t2.interrupt();//中断线程t2,t2释放掉本身的锁,所以t1会获取到rt2然后执行下去
System.out.println("main 线程执行完成!");
}
}
class Worker1 implements Runnable{
static ReentrantLock rt1 = new ReentrantLock();
static ReentrantLock rt2 = new ReentrantLock();
private int i;
public Worker1(int i){
this.i = i;
}
@Override
public void run() {
try{
if(i==1){
//rt1.lock();
rt1.lockInterruptibly();//可被中断的锁
TimeUnit.SECONDS.sleep(1);
//rt2.lock();
rt2.lockInterruptibly();
}else{
//rt2.lock();
rt2.lockInterruptibly();
TimeUnit.SECONDS.sleep(1);
//rt1.lock();
rt1.lockInterruptibly();
}
System.out.println(Thread.currentThread().getName()+" 线程执行结束!");
} catch (InterruptedException e) {
//e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+" 线程释放锁");
if(rt1.isHeldByCurrentThread())//查询当前线程是否持有此锁
rt1.unlock();
if(rt2.isHeldByCurrentThread())//查询当前线程是否持有此锁
rt2.unlock();
}
}
}