1:synchronized
synchronized (lockObject) { // update object state }
synchronized是不错,但它并不完美。它有一些功能性的限制:
ReentrantLock
类实现了Lock
,它拥有与synchronized
相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。(换句话说,当许多线程都想访问共享资源时,JVM 可以花更少的时候来调度线程,把更多时间用在执行线程上。)
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Outputter1 { private Lock lock = new ReentrantLock();// 锁对象 //private Lock lock = new ReentrantLock(true);//公平策略 -->谁等待时间最长,先让谁获取到锁</span> public void output(String name) { lock.lock(); // 得到锁 try { for(int i = 0; i < name.length(); i++) { System.out.print(name.charAt(i)); } } finally { lock.unlock();// 释放锁 } } }
区别:
需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而是用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内!!
3:Condition(线程通信)Condition可以替代传统的线程间通信,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll()。
注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。
Condition的强大之处在于它可以为多个线程间建立不同的Condition
class BoundedBuffer { final Lock lock = new ReentrantLock(); //锁对象 final Condition notFull = lock.newCondition(); //写线程锁 final Condition notEmpty = lock.newCondition(); //读线程锁 final Object[] items = new Object[100];//缓存队列 int putptr; //写索引 int takeptr; //读索引 int count; //队列中数据数目 //写 public void put(Object x) throws InterruptedException { lock.lock(); //锁定 try { // 如果队列满,则阻塞<写线程> while (count == items.length) { notFull.await(); } // 写入队列,并更新写索引 items[putptr] = x; if (++putptr == items.length) putptr = 0; ++count; // 唤醒<读线程> notEmpty.signal(); } finally { lock.unlock();//解除锁定 } } //读 public Object take() throws InterruptedException { lock.lock(); //锁定 try { // 如果队列空,则阻塞<读线程> while (count == 0) { notEmpty.await(); } //读取队列,并更新读索引 Object x = items[takeptr]; if (++takeptr == items.length) takeptr = 0; --count; // 唤醒<写线程> notFull.signal(); return x; } finally { lock.unlock();//解除锁定 } }
Condition
时,允许发生“
虚假唤醒
”,这通常作为对基础平台语义的让步。对于大多数应用程序,这带来的实际影响很小,因为
Condition
应该总是在一个循环中被等待,并测试正被等待的状态声明。某个实现可以随意移除可能的虚假唤醒,但建议应用程序程序员总是假定这些虚假唤醒可能发生,因此总是在一个循环中等待。
4:ReadWriteLock
package cn.crxy.lock; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; public class Cache { /** * 缓存的实现,每个线程只能获得他自己的缓存,也应该是单例的 * 本类没有去实现单例,如果需要的话可以自行去实现 */ private static Map<String, Object> cache = new HashMap<String, Object>(); private static ReadWriteLock rwl = new ReentrantReadWriteLock(); // 允许多个读线程并发,但是不允许写线程并发 public static Object get(String key) { Lock readLock = rwl.readLock(); Object value; try { readLock.lock(); value = cache.get(key); if (value == null) { Lock writeLock = rwl.writeLock(); readLock.unlock(); try { writeLock.lock(); if (value == null) { value = "xxx"; // 查询数据库 cache.put(key, value); } } finally { writeLock.unlock(); } readLock.lock(); } } finally { readLock.unlock(); } return value; } }