java多线程之Lock--显式锁

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();
		}
	}
	
}


猜你喜欢

转载自blog.csdn.net/jiushancunMonkeyKing/article/details/80986249