/*建立一个银行类,银行中有一个金库sum,银行类中有add()方法, * 向其中加钱,每次加钱数量为n */ class Bank { private int sum; public void add(int n) { sum += n; System.out.println(Thread.currentThread().getName()+" sum = "+sum); } } class Cus implements Runnable { private Bank b = new Bank(); public void run() { for(int i=0;i<3;i++) { b.add(100); } } } class Test { public static void main(String args[]) { //两个储户同时操作同一个储蓄账户中的资金 Cus c = new Cus(); new Thread(c).start(); new Thread(c).start(); } }
上面程序运行结果出现了如下结果,
Thread-1 sum = 200
Thread-1 sum = 300
Thread-1 sum = 400
Thread-0 sum = 400
Thread-0 sum = 500
Thread-0 sum = 600
这是一个什么运行结果导致的呢?
分析:1、打印出来的账单中可以看到,开始就以200出现,而不是100,这是由于线程0先调用了add()方法执行sum += n,
此时,账户sum中的资金就是100,就在此时并没有打印sum,线程执行权被线程1获得,线程1调用add()方法,因为
两储户同时操作同一账户(数据共享),账户中已有100再储存100就有200。
2、打印结果中有两个400,这是因为线程1获得执行权后,开始向其账户中存钱,存完后,线程0获得执行权,线程0
继续上一次未完成的造作打印账户信息,而此时账户中的资金信息已经是线程1操作完的结果sum=400,所以打印出了连续
两个相同的信息。
★★★从上面的输出结果中很明显的看出这个由两个储户同时存钱的多线程中存在着线程的安全问题★★★
为了解决这一线程安全问题的产生要明确:
1、哪些是共享数据
2、哪些语句操作共享数据
问题的产生是由于多个线程同时进入操作共享数据语句所产生的,为了不让多个线程同时进入某一代码片段,加入synchronized
同步代码块关键字。
修改后代码:
/*建立一个银行类,银行中有一个金库sum,银行类中有add()方法, * 向其中加钱,每次加钱数量为n */ class Bank { private int sum; Object obj = new Object(); public void add(int n) { synchronized(obj) { //★★★ sum += n; System.out.println(Thread.currentThread().getName()+" sum = "+sum); } } } class Cus implements Runnable { private Bank b = new Bank(); public void run() { for(int i=0;i<3;i++) { b.add(100); } } } class Test { public static void main(String args[]) { //两个储户同时操作同一个储蓄账户中的资金 Cus c = new Cus(); new Thread(c).start(); new Thread(c).start(); } }
输出结果:
Thread-0 sum = 100
Thread-1 sum = 200
Thread-1 sum = 300
Thread-1 sum = 400
Thread-0 sum = 500
Thread-0 sum = 600