Java基础教程:多线程基础——锁机制
Java基础教程:多线程基础——锁机制
显示锁
ReentrantLock
ReentrantLock是一种标准的互斥锁,每次只允许一个线程持有ReentrantLock。
使用ReentrantLock来保护对象状态:
Lock lock = new ReentrantLock(); lock.lock(); try { //更新对象状态 //捕获异常,并在必要时恢复不变性条件 }finally { lock.unlock(); }
如果没有finally来释放Lock,相当于启动了一个定时炸弹。
ReentrantReadWriteLock
互斥锁是一种保守的枷锁策略,它虽然避免了“写/写”冲突,“写/读”冲突,但是同样也避免了“读/读”操作。在许多情况下,数据结构上的操作都是“读操作”。若放宽加锁需求,允许多个执行读操作的线程同时访问数据结构,那么将提高程序的性能。
我们引入读写锁,它允许一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。也就是说当写操作进行时,所有读操作都进入阻塞状态,只有写操作完成后,读操作才能获取到最新状态,避免了脏读的发生。
在如下的代码中,我们使用读写锁封装一个Map,来使其线程安全。
public class ReadWriteMap<K,V> { private final Map<K,V> map; private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final Lock r = lock.readLock(); private final Lock w = lock.writeLock(); public ReadWriteMap(Map<K,V> map){ this.map = map; } public V put(K key,V value){ w.lock(); try { return map.put(key,value); } finally { w.unlock(); } } public V get(Object key){ r.lock(); try { return map.get(key); } finally { r.unlock(); } } }
使用Condition实现等待/通知
关键字Synchronized与wait、notify/All方法相结合可以实现等待/通知模式,类ReentrantLock同样可以实现相同的功能,但是需要借助Condition。
Condition类是JDK5出现的新技术,可以实现 多路通知的功能,也就是在一个Lock对象里可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择性地进行线程通知,在调度线程上更加灵活。
必须在Condition.await()方法调用之前调用Lock.lock()方法获得同步监视器。
MyService类
public class MyService { private Lock lock = new ReentrantLock(); public Condition condition = lock.newCondition(); public void await() { try { lock.lock(); System.out.println("await的等待时间是"+System.currentTimeMillis()); condition.await(); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public void signal() { try { lock.lock(); System.out.println("signal的等待时间是"+System.currentTimeMillis()); condition.signal(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } }
ThreadA类
public class ThreadA extends Thread { private MyService myService; public ThreadA(MyService myService) { this.myService = myService; } @Override public void run() { myService.await(); } }
Main类
public class Main { public static void main(String[] args) throws InterruptedException { MyService myService = new MyService(); ThreadA threadA = new ThreadA(myService); threadA.start(); Thread.sleep(3000); myService.signal(); } }
多个Condition实现通知部分线程
MyService类
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MySevice { private Lock lock = new ReentrantLock(); public Condition conditionA = lock.newCondition(); public Condition conditionB = lock.newCondition(); public void awaitA() { try { lock.lock(); System.out.println("awaitA的start时间是"+System.currentTimeMillis()); conditionA.await(); System.out.println("awaitA的end时间是"+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public void awaitB() { try { lock.lock(); System.out.println("awaitB的start时间是"+System.currentTimeMillis()); conditionB.await(); System.out.println("awaitB的end时间是"+System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } } public void signalA() { try { lock.lock(); System.out.println("signalA的等待时间是"+System.currentTimeMillis()); conditionA.signalAll(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void signalB() { try { lock.lock(); System.out.println("signalB的等待时间是"+System.currentTimeMillis()); conditionB.signalAll(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } }
ThreadA类
public class ThreadA extends Thread { private MySevice myService; public ThreadA(MySevice myService) { this.myService = myService; } @Override public void run() { myService.awaitA(); } }
ThreadB类
public class ThreadB extends Thread { private MySevice myService; public ThreadB(MySevice myService) { this.myService = myService; } @Override public void run() { myService.awaitB(); } }
Main类
public class Main { public static void main(String[] args) throws InterruptedException { MySevice mySevice =new MySevice(); ThreadA threadA = new ThreadA(mySevice); ThreadB threadB = new ThreadB(mySevice); threadA.start(); threadB.start(); Thread.sleep(3000); mySevice.signalA(); } }