lock/condition讲解

发表时间:2017-09-07 16:40:27 浏览量( 17 ) 留言数( 0 )

学习目标:

1、了解lock和condition

2、可以再实践中灵活的使用lock和condition


学习过程:

一、lock/condition的简介

   lock/condition一般配合使用,其作用是:Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。在Condition中,用await()替代wait(),用signal()替代notify(),用signalAll()替代notifyAll(),所以传统线程的通信方式,lock/condition都可以实现,Condition是被绑定到Lock上的,要创建一个Lock的Condition须用newCondition()方法。

    这样看来,Condition和传统的线程通信没什么区别,而且要注意的是采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

    那为什么要使用lock/condition,首先lock的功能更强大,更灵活提供了读写锁,在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,lock它具备可扩展的功能并且在高线程争用的环境下(线程频繁地请求获取已经被其他线程持有的锁) 具有更好的性能;再有Condition可以为多个线程间建立不同的Condition。

    块状锁的缺失移除了发生在同步方法和代码块上自动释放锁的功能。结果是,你通常应该遵循下列对于锁获取和释放的,约定俗成:

Lock lock = ...;

lock.lock(); //再try之前加锁

try{

    //处理任务

}catch(Exception ex){

     

}finally{

    lock.unlock();   //再finally中释放锁

}


二、实例

1、lock的基本使用

(1)资源服务类

public class MyService {

	private final ReentrantLock lock = new ReentrantLock();

	public void method1() {
		lock.lock();
		try {
			System.out.println("我是method1,我获得锁了。");
			Thread.sleep(2000);// 模拟运行两秒
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("我是method1,释放了。");
			lock.unlock();
		}

	}

	public void method2() {
		lock.lock();

		try {
			System.out.println("我是method2,我获得锁了。");
			Thread.sleep(2000);// 模拟运行两秒
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("我是method2,释放了。");
			lock.unlock();
		}

	}
}

(2)运行测试类

public class Run3 {

	public static void main(String[] args) {

		 MyService myService=new MyService();
		 
		 MyThread1 myThread1=new MyThread1(myService);
		 MyThread2 myThread2=new MyThread2(myService);
		 
		 myThread2.start();
		 myThread1.start();
		
		 
	} 
}

2、重写生产者消费者

(1)渠道类:

public class Channel {

	private char c;
	private volatile boolean isWrite = true;
	private final ReentrantLock lock;  //注意要声明为final
	private final Condition condition;

	public Channel() {
		lock = new ReentrantLock();
		condition = lock.newCondition();
	}

	public void putChar(char c) {
		lock.lock();
		try {
			while (!isWrite) {
				try {
					condition.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			this.c = c;
			isWrite = false;
			Thread.sleep(1000);
			condition.signalAll();

		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public char getChar() {
		lock.lock();
		try {
			while (isWrite) {
				try {
					condition.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			isWrite = true;
			condition.signalAll();
		} finally {
			lock.unlock();
			return c;
		}

	}

}

(2)生产者类

public class ThreadPro extends Thread {

	public Channel channel;

	public ThreadPro(Channel channel) {
		this.channel = channel;
	}

	public void run() {
			for (char c = 'a'; c <= 'z'; c++) {
				channel.putChar(c);
				System.out.println("生产端生产了:" + c);
			}


	}

}

(3)消费者类

public class ThreadConsumer extends Thread {
	public Channel channel;

	public ThreadConsumer(Channel channel) {
		this.channel = channel;
	}

	public void run() {
        	char c=channel.getChar();
    		while(c!='z') {
    			System.out.println("消费端消费了:"+c);
    			c=channel.getChar();
    		}
	}
}

(4)运行类

public class Run4 {

	public static void main(String[] args) {
		Channel channel = new Channel();

		ThreadConsumer threadConsumer = new ThreadConsumer(channel);
		ThreadPro threadPro = new ThreadPro(channel);

		
		threadPro.start();
		threadConsumer.start();

	}

}

运行结果

生产端生产了:a

消费端消费了:a

生产端生产了:b

消费端消费了:b

生产端生产了:c

消费端消费了:c

生产端生产了:d

消费端消费了:d

....