前言:

本文内容:ReadWriteLock、阻塞队列BlockingQueue、BlockingQueue四组API

推荐免费JUC并发编程视频:【狂神说Java】JUC并发编程最新版通俗易懂_哔哩哔哩_bilibili

ReadWriteLock

一个ReadWriteLock维护一对关联的locks,一个用于只读操作,一个用于写入。read lock可以由多个阅读器线程同时进行,只要没有作者,write lock是独家的。

读可以多个线程同时读

写只能有一个线程去写

**独占锁(写锁)**一次只能被一个线程占有

共享锁(读锁) 多个线程可以同时占有

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package com.jokerdig.rw;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* @author Joker大雄
* @data 2022/8/22 - 16:23
**/
public class ReadWriteLockDemo {
public static void main(String[] args) {
// MyCache cache = new MyCache();
MyCacheLock cacheLock = new MyCacheLock();
// 写入
for (int i = 0; i <=5 ; i++) {
final int temp = i;
new Thread(()->{
cacheLock .put(temp+"",temp+"");
},String.valueOf(i)).start();

}
// 读取
for (int i = 0; i <=5 ; i++) {
final int temp = i;
new Thread(()->{
cacheLock .get(temp+"");
},String.valueOf(i)).start();

}

}
}

/*
自定义缓存
*/
// 加锁的
class MyCacheLock{
// 模拟的缓存
private volatile Map<String,Object> map = new HashMap<>();
// 读写锁 更加细粒度的控制
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
/*
加锁后,我们希望
写的时候只有一个线程来写
读的时候所有人都可以读
*/
// 存 写入
public void put(String key,Object value){
// 写锁->独占锁
readWriteLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入中...");
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完毕!");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 解锁
readWriteLock.writeLock().unlock();
}
}
// 取 读取
public void get(String key){
// 读锁->共享锁
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取中...");
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完毕!");
} catch (Exception e) {
e.printStackTrace();
} finally {
// 解锁
readWriteLock.readLock().unlock();
}
}

}

// 未加锁 出现插队问题
/*
class MyCache{
// 模拟的缓存
private volatile Map<String,Object> map = new HashMap<>();

// 存 写入
public void put(String key,Object value){
System.out.println(Thread.currentThread().getName()+"写入中...");
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入完毕!");
}
// 取 读取
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取中...");
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取完毕!");
}

}
*/

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1写入中...
1写入完毕!
5写入中...
5写入完毕!
0写入中...
0写入完毕!
2写入中...
2写入完毕!
3写入中...
3写入完毕!
4写入中...
4写入完毕!
0读取中...
0读取完毕!
1读取中...
1读取完毕!
2读取中...
4读取中...
4读取完毕!
3读取中...
3读取完毕!
2读取完毕!
5读取中...
5读取完毕!

Process finished with exit code 0

阻塞队列BlockingQueue

阻塞和队列

写入:如果队列满了,就必须等待,直到队列有位置可以写入,中间的等待产生了阻塞。

读取:如果队列是空的,就必须等待,直到出现可以读取的内容,中间的等待产生了阻塞。

阻塞队列:BlockingQueue

19

BlockingQueue四组API

四组API

方式 抛出异常 有返回值 阻塞等待 超时等待
添加 add() offer() put() offer(参数,时间,时间单位)
移除 remove() poll() take() poll(时间,时间单位)
判断队首元素 element() peek() - -

代码测试

  1. 抛出异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // 抛出异常
    public static void test1(){
    // 队列的大小
    ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);

    System.out.println(arrayBlockingQueue.add("a"));
    System.out.println(arrayBlockingQueue.add("b"));
    System.out.println(arrayBlockingQueue.add("c"));
    // 抛出异常 IllegalStateException: Queue full
    // System.out.println(arrayBlockingQueue.add("d"));

    // 查看队首的元素
    System.out.println(arrayBlockingQueue.element());

    System.out.println("==========================");

    System.out.println(arrayBlockingQueue.remove());
    System.out.println(arrayBlockingQueue.remove());
    System.out.println(arrayBlockingQueue.remove());
    // 抛出异常 java.util.NoSuchElementException
    // System.out.println(arrayBlockingQueue.remove());
    }
  2. 不会抛出异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    // 不抛出异常
    public static void test2(){
    // 队列的大小
    ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);

    System.out.println(arrayBlockingQueue.offer("a"));
    System.out.println(arrayBlockingQueue.offer("b"));
    System.out.println(arrayBlockingQueue.offer("c"));
    // false 返回布尔值 不抛出异常
    // System.out.println(arrayBlockingQueue.offer("d"));

    // 返回队首元素
    System.out.println(arrayBlockingQueue.peek());
    System.out.println("==============================");

    System.out.println(arrayBlockingQueue.poll());
    System.out.println(arrayBlockingQueue.poll());
    System.out.println(arrayBlockingQueue.poll());
    // 返回 null 不抛出异常
    // System.out.println(arrayBlockingQueue.poll());
    }
  3. 阻塞等待

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // 阻塞等待
    public static void test3() throws InterruptedException {
    // 队列的大小
    ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
    arrayBlockingQueue.put("a");
    arrayBlockingQueue.put("b");
    arrayBlockingQueue.put("c");
    // 队列没有位置 它会一直阻塞
    // arrayBlockingQueue.put("d");
    System.out.println("==============================");
    System.out.println(arrayBlockingQueue.take());
    System.out.println(arrayBlockingQueue.take());
    System.out.println(arrayBlockingQueue.take());
    // 队列没有位置 它会一直阻塞
    // System.out.println(arrayBlockingQueue.take());
    }
  4. 超时等待

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 超时等待
    public static void test4() throws InterruptedException {
    // 队列的大小
    ArrayBlockingQueue arrayBlockingQueue = new ArrayBlockingQueue<>(3);
    arrayBlockingQueue.offer("a");
    arrayBlockingQueue.offer("b");
    arrayBlockingQueue.offer("c");
    // 超时等待 设置时间,时间结束如果还在阻塞就直接退出
    arrayBlockingQueue.offer("d",3,TimeUnit.SECONDS);
    System.out.println("==============================");

    System.out.println(arrayBlockingQueue.poll());
    System.out.println(arrayBlockingQueue.poll());
    System.out.println(arrayBlockingQueue.poll());
    // 超时等待 设置时间,时间结束如果还在阻塞就直接退出
    System.out.println(arrayBlockingQueue.poll(3,TimeUnit.SECONDS));
    }