ReentrantReadWriteLock 和 ReentrantLock 不是继承关系,但都是基于 AbstractQueuedSynchronizer 来实现。
lock方法 是基于CAS 来实现的
注意: 在同一线程中,持有读锁后,不能直接调用写锁的lock方法 ,否则会造成死锁。
下面这个例子是在文例子的基础上,将普通锁改为读写锁,并添加账户余额查询的功能,代码如下
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class textBank {
public static void main(String[] args) {
// 创建并发访问的账户 MyCount myCount = new MyCount("95599200901215522", 10000);
// 创建一个锁对象 ReadWriteLock lock = new ReentrantReadWriteLock(false);
// 创建一个线程池 ExecutorService pool = Executors.newFixedThreadPool(2);
// 创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
User u1 = new User("张三", myCount, -4000, lock, false);
User u2 = new User("张三他爹", myCount, 6000, lock, false);
User u3 = new User("张三他弟", myCount, -8000, lock, false);
User u4 = new User("张三", myCount, 800, lock, false);
User u5 = new User("张三他爹", myCount, 0, lock, true);
// 在线程池中执行各个用户的操作
pool.execute(u1);
pool.execute(u2);
pool.execute(u3);
pool.execute(u4);
pool.execute(u5);
// 关闭线程池
pool.shutdown();
}
}
class User implements Runnable {
private String name;
// 用户名 private MyCount myCount;
// 所要操作的账户 private int iocash;
// 操作的金额,当然有正负之分了
private ReadWriteLock myLock;
// 执行操作所需的锁对象 private boolean ischeck;
// 是否查询
User(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {
this.name = name;
this.myCount = myCount;
this.iocash = iocash;
this.myLock = myLock;
this.ischeck = ischeck;
}
public void run() {
if (ischeck) {
// 获取读锁
myLock.readLock().lock();
System.out.println("读:" + name + "正在查询" + myCount + "账户,当前金额为" + myCount.getCash());
// 释放读锁
myLock.readLock().unlock();
} else {
// 获取写锁
myLock.writeLock().lock();
// 执行现金业务
System.out.println("写:" + name + "正在操作" + myCount + "账户,金额为" + iocash + ",当前金额为" + myCount.getCash());
myCount.setCash(myCount.getCash() + iocash);
System.out.println("写:" + name + "操作" + myCount + "账户成功,金额为" + iocash + ",当前金额为" + myCount.getCash());
// 释放写锁
myLock.writeLock().unlock();
}
}
}
class MyCount {
private String oid;
// 账号
private int cash;
// 账户余额
MyCount(String oid, int cash) {
this.oid = oid;
this.cash = cash;
}
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public int getCash() {
return cash;
}
public void setCash(int cash) {
this.cash = cash;
}
@Override
public String toString() {
return "MyCount{" + "oid='" + oid + '\'' + ", cash=" + cash + '}';
}
}
Future的使用,两个线程一块跑异步进行
public class TEXT {
public static void main(String[] args) throws InterruptedException, ExecutionException {
long startTime = System.currentTimeMillis();
// 第一步 网购厨具
Callable<Chuju> onlineShopping = new Callable<Chuju>() {
@Override
public Chuju call() throws Exception {
System.out.println("第一步:下单");
System.out.println("第一步:等待送货");
Thread.sleep(5000); // 模拟送货时间
System.out.println("第一步:快递送到");
return new Chuju();
}
};
FutureTask<Chuju> task = new FutureTask<Chuju>(onlineShopping);
new Thread(task).start();
// 第二步 去超市购买食材
Thread.sleep(2000); // 模拟购买食材时间
Shicai shicai = new Shicai();
System.out.println("第二步:食材到位");
// 第三步 用厨具烹饪食材
if (!task.isDone()) { // 联系快递员,询问是否到货
System.out.println("第三步:厨具还没到,心情好就等着(心情不好就调用cancel方法取消订单)");
}
Chuju chuju = task.get();
System.out.println("第三步:厨具到位,开始展现厨艺");
cook(chuju, shicai);
System.out.println("总共用时" + (System.currentTimeMillis() - startTime) + "ms");
}
// 用厨具烹饪食材
static void cook(Chuju chuju, Shicai shicai) {}
// 厨具类
static class Chuju {}
// 食材类
static class Shicai {}
}
在快递厨具没来时,可以先买菜,在问问快递小哥快递来了吗?如果没来,等会,不想等了就调用cancel方法取消订单
这是API对FutureTask的解释
![](https://i-blog.csdnimg.cn/blog_migrate/bcd21545f6c33524ae38eb249da3dad3.png)