[Java 并发编程实战] 设计线程安全的类的三个方式(含代码) (2)

1) 如果各个状态变量是相互独立的并且互不依赖,并且没有复合操作,那么可以将线程安全性委托给底层的状态变量。如将安全性委托给 value:

1import java.util.concurrent.atomic.AtomicInteger;
2
3public class SafeSequene{
4 private value = new AtomicInteger(0);
5 //返回一个唯一的数值
6 public synchronized int getNext(){
7 return value.incrementAndGet();
8 }
9}

2) 如果各个状态变量之间存在依赖关系,并且存在复合操作,那么是非线程安全的。来看下面一个例子,NumberRange 这个类的各个状态组成部分都是线程安全的,但是存在状态之间的依赖关系,并非互相独立,所以也是非线程安全的。

1import java.util.concurrent.atomic.AtomicInteger;
2
3public class NumberRange{
4
5 //不变性条件:lower <= upper
6 private final AtomicInteger lower = new AtomicInteger(0);//线程安全类
7 private final AtomicInteger upper = new AtomicInteger(0);//线程安全类
8
9 private static boolean flag = true;
10
11 private static volatile boolean stopAllThread = false; //检测到无效状态,停止所有线程并输出,此时lower > upper
12
13 private static int count = 3; //非线程安全,但是不必理会,不影响我们测试
14
15 //检查然后更新
16 public void setLower(int i) {
17 if(i <= upper.get()) { //lower依赖upper的值,有可能upper的值已经失效
18 lower.set(i);
19 }
20 }
21
22 //检查然后更新
23 public void setUpper(int i) {
24 if(i >= lower.get()) { //upper依赖lower的值,有可能lower的值已经失效
25 upper.set(i);
26 }
27 }
28
29 public static void main(String[] args) {
30
31
32 NumberRange nr = new NumberRange();
33 while(stopAllThread == false) {
34 for(int i = 0; i < 10000; i++) {
35
36 if(stopAllThread == true)
37 break;
38
39 new Thread(new Runnable() {
40 @Override
41 public void run() {
42
43 if(stopAllThread == true)
44 return;
45
46 if(flag == true)
47 {
48 flag = false;
49 nr.setLower(count++);
50 }
51 else {
52 flag = true;
53 nr.setUpper(count);
54 }
55 if(nr.lower.get() > nr.upper.get()) //检测到无效状态,lower > upper
56 {
57 stopAllThread = true;
58 System.out.println("state wrong");//打印错误信息
59 System.out.println("lower = " + nr.lower.get() + " upper = " + nr.upper.get());
60 }
61 }
62 }).start();
63 }
64 while(Thread.activeCount() > 1);
65 System.out.println("lower = " + nr.lower.get() + " upper = " + nr.upper.get());
66 }
67 }
68}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgdjxg.html