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(); } } }
相关推荐
通过java语言编写的生产者消费者,实现方法为lock类和condition类的配合完成。
JavaLock与Condition的理解ReentrantLock锁的简单使用技巧共5页.pdf.zip
6.4 使用Lock和Condition 6.5 使用volatile关键字 7. 线程通信: 7.1 使用wait()和notify()方法 7.2 使用Lock和Condition 8. 线程池: 8.1 线程池的概述 8.2 使用Executor框架创建线程池 8.3 线程池的优势和适用场景...
在jdk1.5以后,JAVA提供了Lock类来实现和synchronized一样的功能,并且还提供了Condition来显示线程间通信。 Lock类是Java类来提供的功能,丰富的api使得Lock类的同步功能比synchronized的同步更强大。本文章的所有...
C++11中的各种mutex, lock对象,实际上都是对posix的mutex,condition的封装。不过里面也有很多细节值得学习。 std::mutex 先来看下std::mutex: 包增了一个pthread_mutex_t __m_,很简单,每个函数该干嘛...
主要介绍了Lock、Condition实现简单的生产者消费者模式示例,需要的朋友可以参考下
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
详细介绍了线程同步条件变量condition_variable的使用和它的源码,涉及到unique_lock, mutex, lock_guard, 虚假唤醒和惊群效应。
Condition 的使用 (划重点) Semaphore 的使用 ReadWriteLock 的使用 (划重点) StampedLock 的使用 CountDownLatch 和 CyclicBarrier 的使用 线程池的使用 (划重点) Future 和 FutureTask 的使用 CompletableFuture ...
比较实用,是操作系统很好的教辅资料。很详细的讲解。
此外,Lock接口还有一个带条件的锁——Condition接口的实现类ReentrantLock。这种带条件的锁使得线程可以在一定条件下挂起等待,直到其它线程唤醒它。 在实际使用场景中,例如多个用户同时操作一个银行账户的情况,...
主要介绍了Java多线程中ReentrantLock与Condition详解,需要的朋友可以参考下
Condition 条件变量: 介绍 Lock 接口中的 Condition,它可以实现更复杂的线程等待和通知机制。解释如何使用 await、signal 和 signalAll 方法。 通过这份资源,您将获得关于 Locks 框架中 Lock 接口的深入理解,从...
多线程编程中如果使用Condition对象代替lock, 能够实现在某个事件触发后才处理数据, condition中含有的方法: – wait:线程挂起,收到notify通知后继续运行 – notify:通知其他线程, 解除其它线程的wai状态 – ...
4.线程间通信:lock、condition、wait、notify、notifyAll 5.Lock-free:atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList 6.关于锁的经验介绍 7.并发流程控制手段:CountDownLatch、Barrier 8.定时器:...
Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。 使用Condition的主要方式为:线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件...
4、线程间的协调手段:lock、condition、wait、notify、notifyAll ☆ ☆ ☆ 5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList ☆ ☆ ☆ 6、关于锁使用的经验介绍 7、并发流程控制手段:...
Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用 ...需要特别指出的是,单个 Lock 可能与多个 Condition 对象关联。为了避免兼容性问题,Condition 方法的名称与对应的 Object 版本中的不同。
4、线程间的协调手段:lock、condition、wait、notify、notifyAll☆☆☆ 5、Lock-free: atomic、concurrentMap.putIfAbsent、CopyOnWriteArrayList☆☆☆ 6、关于锁使用的经验介绍 7、并发流程控制手段:...