`
zhangwei_david
  • 浏览: 469600 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

线程安全

 
阅读更多

        线程安全的定义:当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些线程如何交替执行,并且在主调用代码中不需要额外的同步和协调,这个类都能表现出正确的行为,那么这个类就是线程安全的。

       线程安全性可能是非常复杂的,在没有充足同步的情况下,多个线程中的操作执行顺序是不可预测的,甚至会产生非常奇怪的结果。

        如果当多个线程访问一个可变的共享变量时没有使用合适的同步,那么线程就会出现错误。有三种方式可以修复这个问题:

  1. 不在线程间共享变量
  2. 将可变的变量改为不可变的变量
  3. 在访问时使用同步。

有这样一个需求,需要按照序列顺序产生一个序列(不能有重复数据)

 

自增,看似是一个原子操作实际上一个自增包含三个操作步骤:获取变量值, 将变量值加1,将计算结果写入变量。

 

 

/**
 *
 * @author zhangwei_david
 * @version $Id: UnsafeSequence.java, v 0.1 2014年10月24日 下午9:38:54 zhangwei_david Exp $
 */
public class UnsafeSequence {

    
        public static UnsafeSequence unsafeSequence = new UnsafeSequence();
    

    public static UnsafeSequence getInstance() {
        return unsafeSequence;
    }

    private int value;

    public int getNext() {
        return value++;
    }
}

  这个类在单线程下是没有任何问题的,可以顺序的生成一个序列。

 

 

/**
 *
 * @author zhangwei_david
 * @version $Id: OneThread.java, v 0.1 2014年10月25日 下午9:50:32 zhangwei_david Exp $
 */
public class OneThread {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(UnsafeSequence.getInstance().getNext());
        }
    }

}

 

0
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

 那么在多项线程下有是什么样的情况呢?

 

 

import java.util.concurrent.TimeUnit;

/**
 *
 * @author zhangwei_david
 * @version $Id: Test.java, v 0.1 2014年10月24日 下午9:40:41 zhangwei_david Exp $
 */
public class Test {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {
            new Thread(new Runnable() {

                public void run() {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                    }
                    System.out.println(UnsafeSequence.getInstance().getNext());
                }
            }).start();
        }
    }
}
0
15
18
17
21
24
28
16
14
2
0
1
13
12
5
10
31
33
37
11
6
8
9
7
41
43
40
39
38
36
34
35
45
49
58
32
30
29
27
26
25
23
22
4
20
3
19
88
87
86
85
83
84
80
82
81
79
78
77
76
89
90
74
75
73
72
71
70
94
95
69
67
68
66
65
64
63
97
62
61
59
60
57
56
55
54
53
52
51
50
48
47
46
44
42
98
96
93
92
91

        我们可以发现在多线程下,打印的结果是乱序的。 是不是以此就可以断定这个类不是线程安全的内。当然不能,但因的结果是由线程调度和执行的时间决定的。 如果是线程安全的,最终的结果应该自增到99,可是最终没有自增到99,仔细查询结果可以发现有打印了连个零,也就是说有两个线程访问了同一个值,以此可以断定这个类不是线程安全的。

      这是由于多线程要共享相同的内存地址空间,并且是并发运行,因此它们可能会访问或修改其他线程正在使用的变量。如果需要是共享的变量的行为可以预测就需要使用同步。如果没有使用同步,那么无论是编译器、硬件还是在运行时都可以对操作进行优化重新排序,这有助有提升性能但也为开发人员带来了负担。

 那么如何将这个类改为线程安全的呢? 我们只需将获取下一个值的方法改为同步方法既可以解决这个问题。

 

/**
 *
 * @author zhangwei_david
 * @version $Id: Sequence.java, v 0.1 2014年10月24日 下午9:51:20 zhangwei_david Exp $
 */
public class SafeSequence {
    private static class InstanceHolder {
        public static SafeSequence instance = new SafeSequence();
    }

    public SafeSequence getInstance() {
        return InstanceHolder.instance;
    }

    private volatile int value = 0;

    public synchronized int getNext() {
        return value++;
    }
}

 

 

1
0
分享到:
评论
6 楼 cywhoyi 2014-10-29  
dieslrae 写道
zhangwei_david 写道
, 这个volatile  现在是一般不用的!却掉这个关键字依然是线程安全的,因为使用代理内部锁

volatile只是保证可见性,不能保证互斥性

对啊,博主肯定知道了啊,你回答的跟我们想的有出入吗?
5 楼 dieslrae 2014-10-27  
zhangwei_david 写道
, 这个volatile  现在是一般不用的!却掉这个关键字依然是线程安全的,因为使用代理内部锁

volatile只是保证可见性,不能保证互斥性
4 楼 dieslrae 2014-10-27  
cywhoyi 写道
坚决不再计数值上加volatile,如果一定要保证可见性,可以通过原子类操作

atomic也是用的volatile.....
3 楼 cywhoyi 2014-10-26  
zhangwei_david 写道
, 这个volatile  现在是一般不用的!却掉这个关键字依然是线程安全的,因为使用代理内部锁

是啊,相互学习,有空也可以到我博客访问预览下。 
2 楼 zhangwei_david 2014-10-26  
, 这个volatile  现在是一般不用的!却掉这个关键字依然是线程安全的,因为使用代理内部锁
1 楼 cywhoyi 2014-10-26  
坚决不再计数值上加volatile,如果一定要保证可见性,可以通过原子类操作

相关推荐

Global site tag (gtag.js) - Google Analytics