分析
读写锁最重要的需求是:多个线程如果都是在读取数据,如果依然采用加锁的方式,会严重影响效率。所以需要对读写锁进行分离
这种方式适用于:读取的操作比较多
需要考虑以下冲突,否则会出现数据不一致的情况
冲突 | 策略 |
---|---|
读 — 读 | 并行化 |
读 — 写 | 串行化 |
写 — 写 | 串行化 |
读写锁的设计思想就是避免冲突
编码
首先设计的读写锁
- 在获取读锁的时候,需要看看
是否存在正在写的线程
- 在获取写锁的时候,需要看看
是否存在正在写的线程
或者正在读的线程
- 释放锁的就是在完成后,
唤醒正在等待的全部线程
复制代码
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
66public class ReadWriteLock { private int readingReaders = 0;//当前有几个线程正在读 private int waitingReaders = 0;//有几个线程想读,但是读取不了 private int writeingWriters = 0;//正在写的线程数,最多一个 private int waitingWriters = 0;//等待写的线程数 /** * 读锁只需要关心是否有没有人在写 */ public synchronized void readLock() { this.waitingReaders++; try { //如果此时有线程正在写,则不允许读的操作,陷入阻塞 while (writeingWriters > 0) { this.wait(); } //此时没有线程正在写 this.readingReaders++; } catch (InterruptedException e) { e.printStackTrace(); } finally { waitingReaders--; } } /** * 释放读的锁 */ public synchronized void readUnlock() { this.readingReaders--; this.notifyAll(); } /** * 写锁 */ public synchronized void writeLock() { this.waitingWriters++; try { //判断是否有线程正在读或者写 while (readingReaders>0 || writeingWriters>0){ this.wait(); } writeingWriters++; } catch (InterruptedException e) { e.printStackTrace(); } finally { this.waitingWriters--; } } /** * 释放写锁 */ public synchronized void wirteUnlock(){ this.writeingWriters--; this.notifyAll(); } }
验证
设计两个类分别去读取数据和写入数据,然后创建客户端,创建多个写线程和读线程
共享的数据
复制代码
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/** * 共享的数据 */ public class ShareData { private final char [] buffer; private final ReadWriteLock lock = new ReadWriteLock(); public ShareData(int size) { this.buffer = new char[size]; for (int i = 0; i < size; i++) { buffer[i] = '*'; } } /** * 写的操作 * @param c 写的字符 */ public void write(char c){ try { lock.writeLock(); doWrite(c); } finally { lock.wirteUnlock(); } } private void doWrite(char c) { for (int i = 0; i < buffer.length; i++) { buffer[i] = c; } slowly(10); } public char[] read(){ try { lock.readLock(); return doRead(); } finally { lock.readUnlock(); } } /** * 读的操作,返回一个数据的副本 * @return */ private char[] doRead() { char [] newBuf = new char[buffer.length]; for (int i = 0; i < buffer.length; i++) { newBuf[i] = buffer[i]; } slowly(50); return newBuf; } /** * 休眠 * @param time 休眠时间 */ private void slowly(int time) { try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } } }
写的线程
复制代码
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
42public class WriteWorker extends Thread { private final Random random = new Random(System.currentTimeMillis()); private final ShareData data; private final String filer; private int index = 0; public WriteWorker(ShareData data, String filer) { this.data = data; this.filer = filer; } @Override public void run() { try { while (!Thread.interrupted()) { char c = nextChar(); data.write(c); Thread.sleep(random.nextInt(1000)); } } catch (InterruptedException e) { } } /** * 获取一个字符,写到数据 * * @return */ private char nextChar() { char c = filer.charAt(index); index++; if (index >= filer.length()) { index = 0; } return c; } }
读取的线程
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class ReadWorker extends Thread { private final Random random = new Random(); private final ShareData data; public ReadWorker(ShareData data) { this.data = data; } @Override public void run() { try { while (!Thread.interrupted()){ char[] read = data.read(); System.out.println(Thread.currentThread().getName() + " reads " + String.valueOf(read)); Thread.sleep(random.nextInt(1000)); } } catch (InterruptedException e) { } } }
客户端
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Client { public static void main(String[] args) throws InterruptedException { ShareData data = new ShareData(5); new ReadWorker(data).start(); new ReadWorker(data).start(); new ReadWorker(data).start(); new ReadWorker(data).start(); new ReadWorker(data).start(); new WriteWorker(data,"uiiakihlkbjhao465117").start(); new WriteWorker(data,"uiiakihlkbjhao465117").start(); Thread.sleep(10_000); ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); threadGroup.interrupt(); } }
结果:
Thread-1 reads *****
Thread-2 reads *****
Thread-0 reads *****
Thread-3 reads *****
Thread-4 reads *****
Thread-3 reads uuuuu
Thread-4 reads uuuuu
Thread-3 reads uuuuu
Thread-0 reads uuuuu
Thread-3 reads uuuuu
Thread-2 reads iiiii
Thread-1 reads iiiii
Thread-3 reads kkkkk
Thread-1 reads kkkkk
Thread-4 reads kkkkk
最后
以上就是聪慧花卷最近收集整理的关于【详解】Java并发之读写锁分离设计模式分析编码验证的全部内容,更多相关【详解】Java并发之读写锁分离设计模式分析编码验证内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复