2022.8.21 读写锁与阻塞队列
9、读写锁
自定义的缓存,没有加锁,就会出现一个没有写入完成,另一个突然插进来的情况
1 package com.xing.rw; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /** 7 * ReadWriteLock 写只能有一个,读取可以有多个 8 */ 9 public class ReadWriteLock { 10 public static void main(String[] args) { 11 MyCache myCache = new MyCache(); 12 13 14 //写入 15 for (int i = 1; i<= 5; i++){ 16 // 中间变量 17 final int temp = i; 18 new Thread(() -> { 19 myCache.put(temp+"",temp+""); 20 21 },String.valueOf(i)).start(); 22 } 23 24 //读取 25 for (int i = 1; i<= 5; i++){ 26 final int temp = i; 27 new Thread(() -> { 28 myCache.get(temp+""); 29 30 },String.valueOf(i)).start(); 31 } 32 } 33 } 34 /** 35 * 自定义缓存 36 */ 37 class MyCache{ 38 private volatile Map<String,Object> map = new HashMap<>(); 39 //存 40 public void put(String key,Object Value){ 41 System.out.println(Thread.currentThread().getName() + "写入" + key); 42 map.put(key,Value); 43 System.out.println(Thread.currentThread().getName() + "写入OK"); 44 }; 45 //取 46 public void get(String key){ 47 System.out.println(Thread.currentThread().getName() + "读取" + key); 48 Object o = map.get(key); 49 System.out.println(Thread.currentThread().getName() + "读取OK"); 50 }; 51 }
使用读写锁
1 package com.xing.rw; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 import java.util.concurrent.locks.ReentrantReadWriteLock; 6 7 /** 8 * 独占锁(写锁) 一次只能被一个线程占用 9 * 共享锁(读锁) 多个线程可以同时占有 10 * ReadWriteLock 11 * 读- 读 可以共存 12 * 读- 写 不能共存 13 * 写- 写 不能共存 14 * 15 */ 16 public class ReadWriteLock { 17 public static void main(String[] args) { 18 MyCacheLock myCacheLock = new MyCacheLock(); 19 //写入 20 for (int i = 1; i <= 5; i++) { 21 final int temp = i; 22 new Thread(() -> { 23 myCacheLock.put(temp + "", temp + ""); 24 25 }, String.valueOf(i)).start(); 26 } 27 //读取 28 for (int i = 1; i<= 5; i++){ 29 final int temp = i; 30 new Thread(() -> { 31 myCacheLock.get(temp+""); 32 33 },String.valueOf(i)).start(); 34 } 35 } 36 } 37 /** 38 * 自定义缓存 39 */ 40 //加锁的缓存 41 class MyCacheLock{ 42 43 private volatile Map<String,Object> map = new HashMap<>(); 44 private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();//读写锁 45 46 47 //写入的时候,只希望同时只有一个线程往里面写 48 public void put(String key,Object Value){ 49 // 定义写锁readWriteLock.writeLock() 再加锁 50 readWriteLock.writeLock().lock();//写锁 51 try{ 52 System.out.println(Thread.currentThread().getName() + "写入" + key); 53 map.put(key,Value); 54 System.out.println(Thread.currentThread().getName() + "写入OK"); 55 }catch (Exception e){ 56 e.printStackTrace(); 57 }finally { 58 readWriteLock.writeLock().unlock();//解锁 59 } 60 61 }; 62 63 //读 所有人都可以读 64 public void get(String key){ 65 // 读锁readWriteLock.readLock() 66 readWriteLock.readLock().lock(); 67 try{ 68 System.out.println(Thread.currentThread().getName() + "读取" + key); 69 Object o = map.get(key); 70 System.out.println(Thread.currentThread().getName() + "读取OK"); 71 }catch (Exception e){ 72 e.printStackTrace(); 73 }finally { 74 readWriteLock.readLock().unlock(); 75 } 76 77 }; 78 } 79
10、阻塞队列
阻塞队列:
BlockingQueue 是不一个新东西 类似于ArrayList
什么情况下我们会使用阻塞队列:多线程并发,线程池使用的较多
四组API
-
抛出异常
-
不抛出异常
-
阻塞等待
-
超时等待
方式 | 抛出异常 | 有返回值,不抛出异常 | 阻塞等待 | 超时等待 |
---|---|---|---|---|
添加 | add | offer() | put() | offer(,) |
移除 | remove | poll() | take() | poll(,) |
检测队首元素 | element | peek() | - | - |
抛出异常
1 package com.xing.bq; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 /** 5 * 抛出异常 6 */ 7 public class Test1 { 8 public static void main(String[] args) { 9 test1(); 10 } 11 12 public static void test1(){ 13 //参数:队列的大小 14 ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3); 15 16 // 添加元素 返回Boolean值 true:添加成功 17 System.out.println(arrayBlockingQueue.add("A")); 18 System.out.println(arrayBlockingQueue.add("B")); 19 System.out.println(arrayBlockingQueue.add("C")); 20 21 //队列满了,抛出异常IllegalStateException 22 //System.out.println(arrayBlockingQueue.add("D")); 23 24 25 System.out.println("---------------"); 26 System.out.println(arrayBlockingQueue.element());//查看队首的元素 27 28 //谁先进谁先出 29 System.out.println("---------------"); 30 System.out.println(arrayBlockingQueue.remove()); 31 System.out.println(arrayBlockingQueue.remove()); 32 System.out.println(arrayBlockingQueue.remove()); 33 34 //队列空,抛出异常NoSuchElementException 35 //System.out.println(arrayBlockingQueue.remove()); 36 } 37 }
不抛出异常
1 package com.xing.bq; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 /** 5 * 不抛出异常,有返回值 6 */ 7 public class Test2 { 8 public static void main(String[] args) { 9 test2(); 10 } 11 12 public static void test2(){ 13 ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3); 14 15 16 System.out.println(arrayBlockingQueue.offer("A")); 17 System.out.println(arrayBlockingQueue.offer("B")); 18 System.out.println(arrayBlockingQueue.offer("C"));//true 19 System.out.println(arrayBlockingQueue.offer("D"));//false 不抛出异常 返回一个boolean值 20 21 22 System.out.println("-----------------"); 23 System.out.println(arrayBlockingQueue.peek()); 24 25 26 System.out.println("-----------------"); 27 System.out.println(arrayBlockingQueue.poll()); 28 System.out.println(arrayBlockingQueue.poll()); 29 System.out.println(arrayBlockingQueue.poll());//依旧是先进先出 30 System.out.println(arrayBlockingQueue.poll());//null 也不抛出异常 31 } 32 33 } 34 35
阻塞队列
1 package com.xing.bq; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 5 /** 6 * 等待,阻塞(一直阻塞) 7 */ 8 public class Test3 { 9 public static void main(String[] args) { 10 try { 11 test3(); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 public static void test3() throws InterruptedException { 18 ArrayBlockingQueue arrayBlockingQueue =new ArrayBlockingQueue(3); 19 20 //一直阻塞 21 arrayBlockingQueue.put("A"); 22 arrayBlockingQueue.put("B"); 23 arrayBlockingQueue.put("C"); 24 //arrayBlockingQueue.put("D");//队列没有位置了,他会一直等待 25 26 System.out.println("----------------"); 27 System.out.println(arrayBlockingQueue.take()); 28 System.out.println(arrayBlockingQueue.take()); 29 System.out.println(arrayBlockingQueue.take()); 30 //System.out.println(arrayBlockingQueue.take()); //为空 会一直等待 31 } 32 33 } 34
超时等待
1 package com.xing.bq; 2 3 import java.util.concurrent.ArrayBlockingQueue; 4 import java.util.concurrent.TimeUnit; 5 /** 6 * 等待,(超时) 7 */ 8 public class Test4 { 9 public static void main(String[] args) { 10 try { 11 test4(); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 public static void test4() throws InterruptedException { 17 ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue(3); 18 19 arrayBlockingQueue.offer("a"); 20 arrayBlockingQueue.offer("b"); 21 arrayBlockingQueue.offer("c"); 22 arrayBlockingQueue.offer("d", 2,TimeUnit.SECONDS);//等待超过两秒后执行后面的程序 23 24 System.out.println(arrayBlockingQueue.poll()); 25 System.out.println(arrayBlockingQueue.poll()); 26 System.out.println(arrayBlockingQueue.poll()); 27 // arrayBlockingQueue.poll(2,TimeUnit.SECONDS); 28 29 } 30 31 }
同步队列
SynchronousQueue
没有容量,进去一个元素,必须等待取出来之后,才能再往里面放一个元素!
1 package com.xing.bq; 2 3 4 import java.util.concurrent.BlockingQueue; 5 import java.util.concurrent.SynchronousQueue; 6 import java.util.concurrent.TimeUnit; 7 8 /** 9 * 同步队列 10 * 和其他的BlockingQueue不一样,SynchronousQueue 不存储元素 11 * put了一个元素,必须先take取出来,否则不能取出值 12 */ 13 public class SynchronousQueueDemo { 14 public static void main(String[] args) { 15 //同步队列 16 BlockingQueue<String> blockingDeque = new SynchronousQueue<>(); 17 18 new Thread(()->{ 19 try { 20 System.out.println(Thread.currentThread().getName() + "PUT 1"); 21 blockingDeque.put("1");//put():向队列中放入字符串1 22 System.out.println(Thread.currentThread().getName() + "PUT 2"); 23 blockingDeque.put("2"); 24 System.out.println(Thread.currentThread().getName() + "PUT 3"); 25 blockingDeque.put("3"); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 },"T1").start(); 30 new Thread(()->{ 31 try { 32 TimeUnit.SECONDS.sleep(3);//睡3秒 33 System.out.println(Thread.currentThread().getName() + "取出了:" + blockingDeque.take());// take() 取出队列中的元素 34 TimeUnit.SECONDS.sleep(3); 35 System.out.println(Thread.currentThread().getName() + "取出了:" + blockingDeque.take()); 36 TimeUnit.SECONDS.sleep(3); 37 System.out.println(Thread.currentThread().getName() + "取出了:" +blockingDeque.take()); 38 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 },"T2").start(); 43 } 44 } 45
这个例子有点问题,会出现
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix