实现一个读写缓存的操作,假设开始没有加锁的时候,会出现什么情况
public class ReadWriteWithoutLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
// 线程操作资源类,5个线程写
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt + "", tempInt + "");
}, "写操作线程"+i).start();
}
// 线程操作资源类, 5个线程读
for (int i = 1; i <= 5; i++) {
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt + "");
}, "读操作线程"+i).start();
}
}
}
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
public void put(String key, Object value) {
System.out.println(Thread.currentThread().getName() + "\t 正在写入:" + key);
try {
// 模拟网络拥堵,延迟0.3秒
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 写入完成");
}
public void get(String key) {
System.out.println(Thread.currentThread().getName() + "\t 正在读取:" + key);
try {
// 模拟网络拥堵,延迟0.3秒
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object value = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读取完成:" + value);
}
}
运行结果:
写操作线程1 正在写入:1
写操作线程5 正在写入:5
写操作线程4 正在写入:4
写操作线程3 正在写入:3
写操作线程2 正在写入:2
读操作线程1 正在读取:1
读操作线程2 正在读取:2
读操作线程3 正在读取:3
读操作线程4 正在读取:4
读操作线程5 正在读取:5
写操作线程4 写入完成
读操作线程1 读取完成:null
读操作线程4 读取完成:null
写操作线程5 写入完成
写操作线程2 写入完成
读操作线程2 读取完成:null
读操作线程3 读取完成:null
写操作线程3 写入完成
写操作线程1 写入完成
读操作线程5 读取完成:5
Process finished with exit code 0
用ReentrantReadWriteLock解决
public class ReadWriteWithLockDemo {
public static void main(String[] args) {
MyCache2 myCache = new MyCache2();
// 线程操作资源类,5个线程写
for (int i = 1; i <= 5; i++) {
// lambda表达式内部必须是final
final int tempInt = i;
new Thread(() -> {
myCache.put(tempInt + "", tempInt + "");
}, "写操作线程"+i).start();
}
// 线程操作资源类, 5个线程读
for (int i = 1; i <= 5; i++) {
// lambda表达式内部必须是final
final int tempInt = i;
new Thread(() -> {
myCache.get(tempInt + "");
}, "读操作线程"+i).start();
}
}
}
class MyCache2 {
private volatile Map<String, Object> map = new HashMap<>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
// 创建一个写锁
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 正在写入:" + key);
try {
// 模拟网络拥堵,延迟0.3秒
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 写入完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 写锁 释放
rwLock.writeLock().unlock();
}
}
public void get(String key) {
// 读锁
rwLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 正在读取:" + key);
try {
// 模拟网络拥堵,延迟0.3秒
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object value = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读取完成:" + value);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 读锁释放
rwLock.readLock().unlock();
}
}
}
运行结果:
写操作线程1 正在写入:1
写操作线程1 写入完成
写操作线程2 正在写入:2
写操作线程2 写入完成
写操作线程3 正在写入:3
写操作线程3 写入完成
写操作线程5 正在写入:5
写操作线程5 写入完成
读操作线程2 正在读取:2
读操作线程2 读取完成:2
写操作线程4 正在写入:4
写操作线程4 写入完成
读操作线程3 正在读取:3
读操作线程1 正在读取:1
读操作线程4 正在读取:4
读操作线程5 正在读取:5
读操作线程3 读取完成:3
读操作线程1 读取完成:1
读操作线程5 读取完成:5
读操作线程4 读取完成:4
Process finished with exit code 0
示例
假设一个自习室里有7个人,其中有一个是班长,班长的主要职责就是在其它6个同学走了后,关灯,锁教室门,然后走人,因此班长是需要最后一个走的,那么有什么方法能够控制班长这个线程是最后一个执行,而其它线程是随机执行的
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
// 计数器
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 上完自习,离开教室");
countDownLatch.countDown();
}, "线程"+i).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName() + "\t 班长最后关门");
}
}
运行结果:
线程1 上完自习,离开教室
线程5 上完自习,离开教室
线程4 上完自习,离开教室
线程2 上完自习,离开教室
线程3 上完自习,离开教室
线程6 上完自习,离开教室
main 班长最后关门
Process finished with exit code 0
示例
程序演示集齐7个龙珠,召唤神龙
public class SummonTheDragonDemo {
public static void main(String[] args) {
/**
* 定义一个循环屏障,参数1:需要累加的值,参数2 需要执行的方法
*/
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("召唤神龙");
});
for (int i = 1; i <= 7; i++) {
final int tempInt = i;
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t 收集到 第" + tempInt + "颗龙珠");
try {
// 先到的被阻塞,等全部线程完成后,才能执行方法
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
运行结果:
3 收集到 第3颗龙珠
2 收集到 第2颗龙珠
1 收集到 第1颗龙珠
5 收集到 第5颗龙珠
4 收集到 第4颗龙珠
6 收集到 第6颗龙珠
7 收集到 第7颗龙珠
召唤神龙
Process finished with exit code 0
当线程数从7增加到14时候,此时有两次到7得机会,即两次集齐龙珠
1 收集到 第1颗龙珠
4 收集到 第4颗龙珠
13 收集到 第13颗龙珠
14 收集到 第14颗龙珠
11 收集到 第11颗龙珠
12 收集到 第12颗龙珠
6 收集到 第6颗龙珠
3 收集到 第3颗龙珠
10 收集到 第10颗龙珠
5 收集到 第5颗龙珠
9 收集到 第9颗龙珠
8 收集到 第8颗龙珠
7 收集到 第7颗龙珠
召唤神龙
2 收集到 第2颗龙珠
召唤神龙
Process finished with exit code 0
示例
模拟一个抢车位的场景,假设一共有6个车,3个停车位
public class SemaphoreDemo {
public static void main(String[] args) {
/**
* 初始化一个信号量为3,默认是false 非公平锁, 模拟3个停车位
*/
Semaphore semaphore = new Semaphore(3, false);
// 模拟6部车
for (int i = 0; i < 6; i++) {
new Thread(() -> {
try {
// 代表一辆车,已经占用了该车位
semaphore.acquire(); // 抢占
System.out.println(Thread.currentThread().getName() + "\t 抢到车位");
// 每个车停3秒
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t 离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放停车位
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}
运行结果:
1 抢到车位
2 抢到车位
0 抢到车位
0 离开车位
2 离开车位
1 离开车位
4 抢到车位
3 抢到车位
5 抢到车位
5 离开车位
4 离开车位
3 离开车位
Process finished with exit code 0
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有