Java基础教程:多线程基础(4)——Lock的使用

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();
}
}

  

上一篇:Java基础教程:多线程基础——线程池


下一篇:mysql数据库去重复