`
guzizai2007
  • 浏览: 359628 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Lock和Condition

 
阅读更多

1、jdk1.5之前用synchornized和voatile来控制共享对象的并发访问,jdk5.0提供了ReentrantLock。

2、Lock和ReentrantLock:

 

Lock接口里定义了一些抽象的锁操作,有无条件、可轮询、定时、可中断的锁获取操作,ReentrantLock实现了Lock接口,获得ReetrantLock的锁与进入synchronized代码块有相同的内存语义,释放ReentrantLock锁和退出sychronized代码块有相同的内存语义。

 

从上面可以看出,Lock提供了不同形式获取锁方式,而之前通过synchronied修饰代码块的时候,如果有一个线程已经获取对象锁,其他线程访问共享对象的时候就必须无限等待,等待当前线程释放对象锁后再去进行竞争,不能中断那些等待获取锁的线程,而Lock提供了一些其他方法,比如tryLock():如果当前锁可用则获取并返回true,如果不可用则返回false。在方法前加上while(true)就可以实现轮询获取锁。

package com.sxit.test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @功能:tryLock使用
 * @作者: smile
 * @时间:2013-4-18 下午4:03:18
 * @版本:1.0
 */
public class TryLockDemo {

	// 锁
	private final Lock lock = new ReentrantLock();

	public void take() {
			if (lock.tryLock()) {
				try {
					System.out.println("take获取到锁...");
				} catch (Exception e) {
					e.printStackTrace();
				} finally{
					lock.unlock();
				}
			}else{
				System.out.println("take没有获取到锁...");
			}
	}

	public void put() {
			if (lock.tryLock()) {
				try {
					System.out.println("put获取到锁...");
				} catch (Exception e) {
					e.printStackTrace();
				} finally{
					lock.unlock();
				}
			}else{
				System.out.println("put没有获取到锁...");
			}
	}

	public static void main(String[] args) {

		TryLockDemo t = new TryLockDemo();
		Take take = new Take(t);
		Put put = new Put(t);
		Thread t1 = new Thread(take);
		Thread t2 = new Thread(put);

		t1.start();
		t2.start();
	}
}

class Take implements Runnable {

	private TryLockDemo t;

	public Take(TryLockDemo t) {
		this.t = t;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			t.take();
		}
	}
}

class Put implements Runnable {

	private TryLockDemo t;

	public Put(TryLockDemo t) {
		this.t = t;
	}

	@Override
	public void run() {
		while (true) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			t.put();
		}
	}
}

 

 

通过使用tryLock方法就可以让那些等待线程可以不用再无限期等待,可以继续轮询获取锁或者做其他操作。

tryLock还有一个指定时间获取锁的方法,在指定时间内如果锁可用则返回,不可用则线程处于休眠状态。

package com.sxit.test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @功能:tryLock使用
 * @作者: smile
 * @时间:2013-4-18 下午4:03:18
 * @版本:1.0
 */
public class TryLockDemo {

	// 锁
	private final Lock lock = new ReentrantLock();

	public void take() throws Exception {
			if (lock.tryLock(100,TimeUnit.NANOSECONDS)) {
				try {
					System.out.println("take获取到锁...");
				} catch (Exception e) {
					e.printStackTrace();
				} finally{
					lock.unlock();
				}
			}else{
				System.out.println("take 100纳秒内没有获取到锁...");
			}
	}

	public void put() throws Exception {
			if (lock.tryLock(100,TimeUnit.NANOSECONDS)) {
				try {
					System.out.println("put获取到锁...");
				} catch (Exception e) {
					e.printStackTrace();
				} finally{
					lock.unlock();
				}
			}else{
				System.out.println("put 100纳秒内没有获取到锁...");
			}
	}

	public static void main(String[] args) {

		TryLockDemo t = new TryLockDemo();
		Take take = new Take(t);
		Put put = new Put(t);
		Thread t1 = new Thread(take);
		Thread t2 = new Thread(put);

		t1.start();
		t2.start();
	}
}

class Take implements Runnable {

	private TryLockDemo t;

	public Take(TryLockDemo t) {
		this.t = t;
	}

	@Override
	public void run() {
		while (true) {
			try {
				t.take();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

class Put implements Runnable {

	private TryLockDemo t;

	public Put(TryLockDemo t) {
		this.t = t;
	}

	@Override
	public void run() {
		while (true) {
			try {
				t.put();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 还有一种是lockInterruptibly():可中断的锁获取,当线程在获取锁的时候,如果有其他线程调用该线程的interrupt方法中断线程,这时不会再去尝试获取锁,而会抛出一个InterruptedException异常。而正常的lock()方法不允许中断线程,即使调用了interrupt()方法还是会继续尝试获取锁,最后获取到锁后再把线程设置为interrupt状态,然后再中断。 而且使用lockInterruptibly获取锁的时候,如果线程被中断了,会抛出异常,并且会把线程的中断状态移除。

package com.sxit.test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @功能:lockInterruptibly使用
 * @作者: smile
 * @时间:2013-4-18 下午4:03:18
 * @版本:1.0
 */
public class TryLockDemo {

	// 锁
	private final Lock lock = new ReentrantLock();

	public void interrupt() {
		try {
			lock.lockInterruptibly();
			System.out.println("打印一下");
			//中断前状态
			System.out.println("中断前状态:"+Thread.currentThread().isInterrupted());
			//中断当前线程
			Thread.currentThread().interrupt();
			//中断后状态
			System.out.println("中断后状态:"+Thread.currentThread().isInterrupted());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			//中断最后状态
			System.out.println("中断最后状态:"+Thread.currentThread().isInterrupted());
			lock.unlock();
		}
	}

	public static void main(String[] args) {

		TryLockDemo t = new TryLockDemo();
		Iterrupt i = new Iterrupt(t);
		Thread t1 = new Thread(i);
		
		t1.start();
		
	}
}


class Iterrupt implements Runnable {

	private TryLockDemo t;

	public Iterrupt(TryLockDemo t) {
		this.t = t;
	}

	@Override
	public void run() {
		while (true) {
			try {
				t.interrupt();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

 

还有一个方法是newCondition(),返回一个Condition实例。这个方法时返回一个绑定这个Lock实例的条件对象实例。

 

之前使用synchronized的时候,比如生产者和消费者模型中有take和put两个操作,当队列为空时会调用list.wait(),当队列满的时候也会调用list.wait(),就是把当前线程加入到list对象的锁等待池中,而当队列不为空或者队列不是满的时候我们会调用notifyAll或者notify,比如take中调用notify时,它会从锁等待池中随机选一个线程让它进入可运行状态,等待锁释放后去竞争锁,但是这里就有一个问题,其实我们这里需要唤醒的是take线程,但是使用notify的时候随机性很强,很有可能他唤醒的是一个put线程或者别的线程,当然可以使用notifyAll,他会唤醒对象锁池中的所有线程,但是等锁释放后,还是只有一个锁能够竞争到资源进入运行状态,所以这样不能明确快速的指定具体要唤醒的线程。

 

现在jdk5.0提供了Condition,通过lock.newCondition()可以获得绑定当前锁的条件对象,每个条件对象都维护相对于自己这个条件的线程等待池,比如队列非空,可以创建一个Condition not_empty = lock.newCondition();  当take的时候如果队列为空,则not_empty.await(),这样当前线程由这个条件对象来维护,当队列非空的时候就可以通过调用not_empty.sigal()来唤醒那些需要取元素的线程。这样就能把各种线程在不同条件下进行细致分类,灵活操作。不用像之前那样直接用个notifyAll,使用notifyAll把不同条件需求的线程全绑定在一个队列中,一个条件满足就需要唤醒全部线程,然后相互竞争锁,既不精确性能也差。

 

一个简单的生产者和消费者模型实例:

package com.sxit.test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @功能:使用Lock Conditon
 * @作者: smile
 * @时间:2013-4-18 下午5:18:07
 * @版本:1.0
 */
public class Test05 {
	
	public static Lock lock = new ReentrantLock();;
	// 容器已满  綁定product線程
	public static Condition full = lock.newCondition();
	// 容器为空  綁定consumer線程
	public static Condition empty = lock.newCondition();

	public static void main(String[] args) {
		List list = new ArrayList(12);
		Product product = new Product(list, 10);
		Consumer consumer = new Consumer(list, 0);
		
		Thread t1 = new Thread(product);
		Thread t2 = new Thread(consumer);
		
		t1.start();
		t2.start();
	}
	
	// 生产
	static class Product implements Runnable {

		private List list;
		private int maxCount;

		public Product(List list, int maxCount) {
			super();
			this.list = list;
			this.maxCount = maxCount;
		}

		@Override
		public void run() {
			while(true){
				if (lock.tryLock()) {
					try {
						if (getSize() >= maxCount) {
							System.out.println("容器已滿,product線程加入池中...");
							full.await();
						}
						System.out.println("開始生產....");
						list.add(new Object());
						//喚醒消費者線程
						empty.signal();
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						lock.unlock();
					}
				} else {
					System.out.println("未获取生产资格...");
				}
			}
		}

		public int getSize() {
			return list.size();
		}
	}

	// 消费
	static class Consumer implements Runnable {

		private List list;
		private int minCount;

		public Consumer(List list, int minCount) {
			super();
			this.list = list;
			this.minCount = minCount;
		}

		@Override
		public void run() {
			while(true){
				if (lock.tryLock()) {
					try {
						if (getSize() <= minCount) {
							System.out.println("容器已空,consumer線程加入池中...");
							empty.await();
						}
						System.out.println("開始消費....");
						list.remove(0);
						//喚醒生產者線程
						full.signal();
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						lock.unlock();
					}
				} else {
					System.out.println("未获取消费资格...");
				}
			}
		}
		
		public int getSize() {
			return list.size();
		}
	}
	
}

 

 

 

 

 

 

 

分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    生产者-消费者(lock和condition).zip

    在这个场景中,"生产者-消费者(lock和condition).zip"的文件内容可能包含一个使用Java语言实现的示例,它利用了`java.util.concurrent.locks.Lock`接口和`Condition`接口来解决这个问题。 `Lock`接口是Java并发库...

    java中的Lock类和Condition类.docx

    Java中的Lock类与Condition类是Java并发编程的重要组成部分,它们为多线程环境下的同步提供了更为灵活和强大的控制。在JDK 1.5及之后的版本中,Lock类作为替代synchronized关键字的一种方式出现,提供了更精细的锁...

    JavaLock与Condition的理解Reentran

    本文将深入探讨JavaLock中的ReentrantLock(可重入锁)以及与其紧密相关的Condition接口,帮助你理解它们的工作原理和应用场景。 **一、ReentrantLock可重入锁** ReentrantLock是Java.util.concurrent.locks包下的...

    Java并发编程(20)并发新特性-Lock锁和条件变量(

    使用Lock和Condition,生产者和消费者可以独立地控制何时进入等待状态,何时继续执行。当队列满时,生产者会调用condition.await()等待,直到消费者消费了一些数据并调用condition.signal();同样,当队列空时,消费...

    Java中的Runnable接口最全讲义

    6.4 使用Lock和Condition 6.5 使用volatile关键字 7. 线程通信: 7.1 使用wait()和notify()方法 7.2 使用Lock和Condition 8. 线程池: 8.1 线程池的概述 8.2 使用Executor框架创建线程池 8.3 线程池的优势和适用场景...

    多线程编程的核心思想.doc

    多线程编程的核心思想 多线程编程的核心思想是指在多线程环境下如何实现线程安全、...多线程编程的核心思想是通过 Lock 和 Condition 接口来实现线程安全和同步机制,并使用 AQS 底层实现来实现锁和 Condition 接口。

    wait,notify等线程知识.pdf

    通过使用wait()、notify()和notifyAll(),或者Lock和Condition,开发者可以控制线程的执行顺序,确保共享资源的安全访问。 7. **死锁和活锁问题**: 使用wait/notify机制时,需要注意死锁和活锁问题。死锁发生在两...

    Java基于Lock的生产者消费者模型示例

    本示例中,我们使用了Lock和Condition来实现生产者消费者模型,避免了使用synchronized关键字的方式,而是使用了Lock和Condition来实现线程同步和通信,提高了程序的性能和可读性。 知识点: * Java中的生产者消费...

    locks框架:接口.pdf

    在实际使用中,Lock和Condition的配合使用可以实现复杂的数据结构,例如生产者-消费者模型中的缓冲区,如示例代码中的BoundedBuffer类。它使用了ReentrantLock来保护共享状态,并通过Condition来控制生产者和消费者...

    Java并发编程解析 | 解析AQS基础同步器的设计与实现

    AQS是Java中解决同步和互斥问题的基础同步器,通过Lock和Condition两个接口来实现管程。Lock用于解决互斥问题,Condition用于解决同步问题。AQS的设计和实现是基于管程技术的,管程是解决同步和互斥问题的有效方法。...

    ConditionVariablesJAVA多线程[定义].pdf

    而Condition接口则代表了一个条件变量,它被绑定到一个Lock对象上,并提供了一系列方法,例如await()、signal()和signalAll(),分别用于挂起当前线程、唤醒一个等待的线程以及唤醒所有等待的线程。 在上述提供的...

    java项目开发总结.docx

    * lock 和 Condition 等同步机制 九、Web 开发 * HttpServlet、doGet、doPost 等 servlet 方法 * HttpServletRequest 和 HttpServletResponse 等 servlet 接口 * request.getParameter()、request.setAttribute() ...

    测试开发面试经验总结.docx

    多线程的实现方式包括继承Thread类和实现Runnable接口,面试中可能还会讨论线程同步和通信的方法,如wait、sleep、notify和notifyAll,以及线程间的共享变量、wait/notify机制、Lock和Condition等。 此外,面试中还...

    nachos实验二 线程与同步

    1. 使用 Thread::Sleep 实现锁机制和条件变量:在这一部分中,需要修改 nachos-3.4/code/threads/synch.h 和 nachos-3.4/code/threads/synch.cc 文件,实现 Lock 和 Condition 类的接口声明和实现。 2. 使用 ...

    Thread基础知识点笔记总结

    Thread 基础知识点笔记总结 Thread 是 Java 中最...传统生产者消费者问题可以用 lock 和 condition 一起控制,用 condition 的 await()和 signal()对生产者和消费者进行等待和唤醒,保证生产一个数据消费一个数据。

    nachos实验报告 3 lab3

    这为构建更复杂的锁机制,如Semaphore、Lock和Condition提供了基础。 **内容二:任务完成情况** 实验3包括了以下几个Exercise: - Exercise1:实现了Semaphore的概念,包括P()和V()操作。P()操作中使用while循环和...

    java面试题150题.docx

    线程和线程同步是多线程编程的核心概念,Java提供了synchronized关键字、wait/notify机制以及更高级的Lock和Condition接口来保证并发安全。集合框架是Java中存储和操作数据的重要工具,包括List、Set、Map等,而迭代...

    Java多线程演示系统.zip

    Java提供了丰富的线程同步机制来防止线程间的数据竞争问题,主要包括synchronized关键字、volatile变量、Lock和Condition接口、CountDownLatch、CyclicBarrier、Semaphore等。synchronized提供互斥访问,保证同一...

Global site tag (gtag.js) - Google Analytics