问题的出现

上代码

  [plaintext]
1
2
3
4
5
6
7
8
9
10
11
12
public class Num { private int num; public int getNum() { return num; } public int add(int num) { this.num += num; return this.num; } }

测试类

  [plaintext]
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
public class ErrorDemo implements Runnable { private Num num = new Num(); @Override public void run() { for(int i = 0; i < 3; i++) { try { Thread.sleep(1000); num.add(10); System.out.println(Thread.currentThread().getName()+" value is " + num.getNum()); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Runnable runnable = new ErrorDemo(); Thread thread = new Thread(runnable, "thread-01"); Thread thread2 = new Thread(runnable, "thread-02"); thread.start(); thread2.start(); } }

结果

  [plaintext]
1
2
3
4
5
6
7
8
thread-01 value is 20 thread-02 value is 20 thread-02 value is 40 thread-01 value is 40 thread-02 value is 50 thread-01 value is 60 Process finished with exit code 0

这个结果是不准确的。原因是多个线程不加限制的共同操作同一个数据导致

该怎么解决这个问题呢?

#线程的同步

知道导致问题的原因,解决起来也不是很困难。 我们可以限制:每次只有一个线程可以操作数据 具体实现一般需满足以下2个条件

  • 将竞争访问的资源变量设置为private
  • 使用关键字synchronized同步修改变量的代码

##同步方法 对ErrorDemo中的run()加上关键字

  [plaintext]
1
2
3
4
5
6
7
8
9
10
11
12
@Override public synchronized void run() { for(int i = 0; i < 3; i++) { try { Thread.sleep(1000); num.add(10); System.out.println(Thread.currentThread().getName()+" value is " + num.getNum()); } catch (InterruptedException e) { e.printStackTrace(); } } }

结果:

  [plaintext]
1
2
3
4
5
6
7
8
thread-01 value is 10 thread-01 value is 20 thread-01 value is 30 thread-02 value is 40 thread-02 value is 50 thread-02 value is 60 Process finished with exit code 0

##同步代码块 上面的同步方法,也可以写成

  [plaintext]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override public void run() { for(int i = 0; i < 3; i++) { try { synchronized (this) { Thread.sleep(1000); num.add(10); System.out.println(Thread.currentThread().getName()+" value is " + num.getNum()); } } catch (InterruptedException e) { e.printStackTrace(); } } }

注意

  • 如果是同步静态方法,代码块中,this应替换成className.class
  • java.util.concurrent.locks Lock接口也可完成类似功能,且思路更为清晰。

相关内容

线程-001-线程简介

线程-002-基本的线程机制

线程-003-线程的同步与锁

线程-004-线程间的协作及状态迁移