Java 多线程五:锁三
发布时间:2023-04-17 11:35:18 所属栏目:教程 来源:
导读:StampedLock其实是对读写锁的一种改进,它支持在读同时进行一个写操作,也就是说,它的性能将会比读写锁更快。
更通俗的讲就是在读锁没有释放的时候是可以获取到一个写锁,获取到写锁之后,读锁阻塞,这一点和读写
更通俗的讲就是在读锁没有释放的时候是可以获取到一个写锁,获取到写锁之后,读锁阻塞,这一点和读写
|
StampedLock其实是对读写锁的一种改进,它支持在读同时进行一个写操作,也就是说,它的性能将会比读写锁更快。 更通俗的讲就是在读锁没有释放的时候是可以获取到一个写锁,获取到写锁之后,读锁阻塞,这一点和读写锁一致,唯一的区别在于读写锁不支持在没有释放读锁的时候获取写锁。 StampedLock 有三种模式: 悲观读:允许多个线程获取悲观读锁。 写锁:写锁和悲观读是互斥的。 乐观读:无锁机制,类似于数据库中的乐观锁,它支持在不释放乐观读的时候是可以获取到一个写锁。 参考: 有没有比读写锁更快的锁? 示例代码: 悲观读 + 写锁: package git.snippets.juc; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.StampedLock; import java.util.logging.Logger; // 悲观读 + 写锁 public class StampedLockpessimistic { private static final Logger log = Logger.getLogger(StampedLockpessimistic.class.getName()); private static final StampedLock lock = new StampedLock(); //缓存中存储的数据 private static final Map<String, String> mapCache = new HashMap<>(); //模拟数据库存储的数据 private static final Map<String, String> mapDb = new HashMap<>(); static { mapDb.put("zhangsan", "你好,我是张三"); mapDb.put("sili", "你好,我是李四"); } private static void getInfo(String name) { //获取悲观读 long stamp = lock.readLock(); log.info("线程名:" + Thread.currentThread().getName() + " 获取了悲观读锁" + " 用户名:" + name); try { if ("zhangsan".equals(name)) { log.info("线程名:" + Thread.currentThread().getName() + " 休眠中" + " 用户名:" + name); Thread.sleep(3000); log.info("线程名:" + Thread.currentThread().getName() + " 休眠结束" + " 用户名:" + name); } String info = mapCache.get(name); if (null != info) { log.info("在缓存中获取到了数据"); return; } } catch (InterruptedException e) { log.info("线程名:" + Thread.currentThread().getName() + " 释放了悲观读锁"); e.printstacktrace(); } finally { //释放悲观读 lock.unlock(stamp); } //获取写锁 stamp = lock.writeLock(); log.info("线程名:" + Thread.currentThread().getName() + " 获取了写锁" + " 用户名:" + name); try { //判断一下缓存中是否被插入了数据 String info = mapCache.get(name); if (null != info) { log.info("获取到了写锁,再次确认在缓存中获取到了数据"); return; } //这里是往数据库获取数据 String infoByDb = mapDb.get(name); //将数据插入缓存 mapCache.put(name, infoByDb); log.info("缓存中没有数据,在数据库获取到了数据"); } finally { //释放写锁 log.info("线程名:" + Thread.currentThread().getName() + " 释放了写锁" + " 用户名:" + name); lock.unlock(stamp); } } public static void main(String[] args) { //线程1 Thread t1 = new Thread(() -> { getInfo("zhangsan"); }); //线程2 Thread t2 = new Thread(() -> { getInfo("lisi"); }); //线程启动 t1.start(); t2.start(); //线程同步 try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printstacktrace(); } } } 乐观读: package git.snippets.juc; import java.util.concurrent.locks.StampedLock; import java.util.logging.Logger; // 乐观写 public class StampedLockOptimistic { private static final Logger log = Logger.getLogger(StampedLockOptimistic.class.getName()); private static final StampedLock lock = new StampedLock(); private static int num1 = 1; private static int num2 = 1; /** * 修改成员变量的值,+1 * * @return */ private static int sum() { log.info("求和方法被执行了"); //获取乐观读 long stamp = lock.tryOptimisticRead(); int cnum1 = num1; int cnum2 = num2; log.info("获取到的成员变量值,cnum1:" + cnum1 + " cnum2:" + cnum2); try { //休眠3秒,目的是为了让其他线程修改掉成员变量的值。 Thread.sleep(3000); } catch (InterruptedException e) { e.printstacktrace(); } //判断在运行期间是否存在写操作 true:不存在 false:存在 if (!lock.validate(stamp)) { log.info("存在写操作!"); //存在写锁 //升级悲观读锁 stamp = lock.readLock(); try { log.info("升级悲观读锁"); cnum1 = num1; cnum2 = num2; log.info("重新获取了成员变量的值=========== cnum1=" + cnum1 + " cnum2=" + cnum2); } finally { //释放悲观读锁 lock.unlock(stamp); } } return cnum1 + cnum2; } //使用写锁修改成员变量的值 private static void updateNum() { long stamp = lock.writeLock(); try { num1 = 2; num2 = 2; } finally { lock.unlock(stamp); } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { int sum = sum(); log.info("求和结果:" + sum); }); t1.start(); //休眠1秒,目的为了让线程t1能执行到获取成员变量之后 Thread.sleep(1000); updateNum(); t1.join(); log.info("执行完毕"); } } (编辑:汽车网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐
