当前位置:首页 > 开发 > 编程语言 > 多线程 > 正文

线程安全

发表于: 2014-10-25   作者:zhangwei_david   来源:转载   浏览:
摘要:         线程安全的定义:当多个线程访问某个类时,不管运行环境采用何种调度方式或者这些线程如何交替执行,并且在主调用代码中不需要额外的同步和协调,这个类都能表现出正确的行为,那么这个类就是线程安全的。        线程安全性可能是非常复杂的

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

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

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

  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++;
    }
}

 

 

线程安全

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
1,原子操作 通常cpu的最小执行单元是一条指令,是不会被打断的。我们把单条指令的操作成为是原子的
一、本文主要描述线程安全: 1.1: 什么是线程安全 1.2: 保持同步的原子性 1.3: 锁机制 1.4: 用
一、本文主要描述线程安全: 1.1: 什么是线程安全 1.2: 保持同步的原子性 1.3: 锁机制 1.4: 用
线程安全: 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如
  ArrayList和Vector有什么区别?   HashMap和HashTable有什么区别?   StringBuilder和StringB
我们知道Spring通过各种模板类降低了开发者使用各种数据持久技术的难度。这些模板类都是线程安全的
线程安全 [ 编辑本段] 什么是线程安全?   如果你的代码所在的进程中有多个线程在同时运行,而这
Servlet的多线程机制 1. 变量的线性安全:这里的变量指字段和共享数据(如表单参数值)。 将参数变
Servlet/JSP技术和ASP、PHP等相比,由于其多线程运行而具有很高的执行效率。由于Servlet/JSP默认是以
synchronized() 在线程运行的时候,有时会出现线程安全问题 例如:买票程序,有可能会出现不同窗口
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号