线程安全问题

Posted by Young Ken on 2016-09-03

有很多人喜欢用计数器 i++,这样很方便,在单线程下没有一点问题,每次都是你想要的结果,但是放到多线程中,结果就会出乎意料。

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
public class Test
{
public int values;
public static void main(String args[])
{
Test test = new Test();
while (true)
{
new TestThread(test).start();
}
}
//这里被多线程调用
public int getValues() {
System.out.println(values);
return values++;
}
}
class TestThread extends Thread
{
private Test test;
TestThread(Test test)
{
this.test = test;
}
@Override
public void run() {
super.run();
test.getValues();
}
}

输出结果:
0
1
2
3
4
5
6
7
8
9
9
11
12
13
14
14
14

15
16
19
20
21
22
23
很容易看出来结果不对,出现了3次14。为什么会出现这样的结果?
value++这样简单的操作其实包括三个步骤

  • 取出value
  • 将value加1
  • 最后把value附上新的计算值

    那么怎么解决这样的问题,简单的方式有两种
  • 把getValue()变成线性安全的方法,添加synchronized。
    1
    2
    3
    4
    5
    public synchronized int getValues() {
    return values++;
    }
    //把value变成线程安全的Int,AtomicInteger。
    public AtomicInteger inter = new AtomicInteger();

那么问题来了,两个方法哪个性能更高。
运行了100000次,时间几乎一样,但是大部分时间AtomicInteger快了一点点,大家可以亲自测试一下。