Java多线程之Lock的使用 .


01.import java.util.concurrent.ExecutorService;
02.import java.util.concurrent.Executors;
03.import java.util.concurrent.Future;
04.import java.util.concurrent.locks.Lock;
05.import java.util.concurrent.locks.ReadWriteLock;
06.import java.util.concurrent.locks.ReentrantLock;
07.import java.util.concurrent.locks.ReentrantReadWriteLock;
08.
09./**
10. * Lockers
11. * 在多线程编程里面一个重要的概念是锁定,如果一个资源是多个线程共享的,为了保证数据的完整性,
12. * 在进行事务性操作时需要将共享资源锁定,这样可以保证在做事务性操作时只有一个线程能对资源进行操作,
13. * 从而保证数据的完整性。在5.0以前,锁定的功能是由Synchronized关键字来实现的。
14. */
15.public class Lockers {
16.
17. /**
18. * 测试Lock的使用。在方法中使用Lock,可以避免使用Synchronized关键字。
19. */
20. public static class LockTest {
21.
22. Lock lock = new ReentrantLock();// 锁
23. double value = 0d; // 值
24. int addtimes = 0;
25.
26. /**
27. * 增加value的值,该方法的操作分为2步,而且相互依赖,必须实现在一个事务中
28. * 所以该方法必须同步,以前的做法是在方法声明中使用Synchronized关键字。
29. */
30. public void addValue(double v) {
31. lock.lock();// 取得锁
32. System.out.println("LockTest to addValue: " + v + " "
33. + System.currentTimeMillis());
34. try {
35. Thread.sleep(1000);
36. } catch (InterruptedException e) {
37. }
38. this.value += v;
39. this.addtimes++;
40. lock.unlock();// 释放锁
41. }
42.
43. public double getValue() {
44. return this.value;
45. }
46. }
47. public static void testLockTest() throws Exception{
48. final LockTest lockTest = new LockTest();
49. // 新建任务1,调用lockTest的addValue方法
50. Runnable task1 = new Runnable(){
51. public void run(){
52. lockTest.addValue(55.55);
53. }
54. };
55. // 新建任务2,调用lockTest的getValue方法
56. Runnable task2 = new Runnable(){
57. public void run(){
58. System.out.println("value: " + lockTest.getValue());
59. }
60. };
61. // 新建任务执行服务
62. ExecutorService cachedService = Executors.newCachedThreadPool();
63. Future future = null;
64. // 同时执行任务1三次,由于addValue方法使用了锁机制,所以,实质上会顺序执行
65. for (int i=0; i<3; i++){
66. future = cachedService.submit(task1);
67. }
68. // 等待最后一个任务1被执行完
69. future.get();
70. // 再执行任务2,输出结果
71. future = cachedService.submit(task2);
72. // 等待任务2执行完后,关闭任务执行服务
73. future.get();
74. cachedService.shutdownNow();
75. }
76.
77. /**
78. * ReadWriteLock内置两个Lock,一个是读的Lock,一个是写的Lock。
79. * 多个线程可同时得到读的Lock,但只有一个线程能得到写的Lock,
80. * 而且写的Lock被锁定后,任何线程都不能得到Lock。ReadWriteLock提供的方法有:
81. * readLock(): 返回一个读的lock
82. * writeLock(): 返回一个写的lock, 此lock是排他的。
83. * ReadWriteLockTest很适合处理类似文件的读写操作。
84. * 读的时候可以同时读,但不能写;写的时候既不能同时写也不能读。
85. */
86. public static class ReadWriteLockTest{
87. // 锁
88. ReadWriteLock lock = new ReentrantReadWriteLock();
89. // 值
90. double value = 0d;
91. int addtimes = 0;
92.
93. /**
94. * 增加value的值,不允许多个线程同时进入该方法
95. */
96. public void addValue(double v) {
97. // 得到writeLock并锁定
98. Lock writeLock = lock.writeLock();
99. writeLock.lock();
100. System.out.println("ReadWriteLockTest to addValue: " + v + " "
101. + System.currentTimeMillis());
102. try {
103. Thread.sleep(1000);
104. } catch (InterruptedException e) {
105. }
106. try {
107. // 做写的工作
108. this.value += v;
109. this.addtimes++;
110. } finally {
111. // 释放writeLock锁
112. writeLock.unlock();
113. }
114. }
115. /**
116. * 获得信息。当有线程在调用addValue方法时,getInfo得到的信息可能是不正确的。
117. * 所以,也必须保证该方法在被调用时,没有方法在调用addValue方法。
118. */
119. public String getInfo() {
120. // 得到readLock并锁定
121. Lock readLock = lock.readLock();
122. readLock.lock();
123. System.out.println("ReadWriteLockTest to getInfo "
124. + System.currentTimeMillis());
125. try {
126. Thread.sleep(1000);
127. } catch (InterruptedException e) {
128. }
129. try {
130. // 做读的工作
131. return this.value + " : " + this.addtimes;
132. } finally {
133. // 释放readLock
134. readLock.unlock();
135. }
136. }
137. }
138.
139. public static void testReadWriteLockTest() throws Exception{
140. final ReadWriteLockTest readWriteLockTest = new ReadWriteLockTest();
141. // 新建任务1,调用lockTest的addValue方法
142. Runnable task_1 = new Runnable(){
143. public void run(){
144. readWriteLockTest.addValue(55.55);
145. }
146. };
147. // 新建任务2,调用lockTest的getValue方法
148. Runnable task_2 = new Runnable(){
149. public void run(){
150. System.out.println("info: " + readWriteLockTest.getInfo());
151. }
152. };
153. // 新建任务执行服务
154. ExecutorService cachedService_1 = Executors.newCachedThreadPool();
155. Future future_1 = null;
156. // 同时执行5个任务,其中前2个任务是task_1,后两个任务是task_2
157. for (int i=0; i<2; i++){
158. future_1 = cachedService_1.submit(task_1);
159. }
160. for (int i=0; i<2; i++){
161. future_1 = cachedService_1.submit(task_2);
162. }
163. // 最后一个任务是task_1
164. future_1 = cachedService_1.submit(task_1);
165. // 这5个任务的执行顺序应该是:
166. // 第一个task_1先执行,第二个task_1再执行;这是因为不能同时写,所以必须等。
167. // 然后2个task_2同时执行;这是因为在写的时候,就不能读,所以都等待写结束,
168. // 又因为可以同时读,所以它们同时执行
169. // 最后一个task_1再执行。这是因为在读的时候,也不能写,所以必须等待读结束后,才能写。
170.
171. // 等待最后一个task_2被执行完
172. future_1.get();
173. cachedService_1.shutdownNow();
174. }
175.
176. public static void main(String[] args) throws Exception{
177. Lockers.testLockTest();
178. System.out.println("---------------------");
179. Lockers.testReadWriteLockTest();
180. }
181.}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值