多线程中出现的一个的奇怪现象
class Bank
{
private int sum = 0;
public void add(int n)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
sum = sum + n;
System.out.println(Thread.currentThread().getName()+"sum="+ sum);
// System.out.println(sum);
}
}
class Cus implements Runnable
{
Bank bank = new Bank();
public void run()
{
for(int x= 1; x <=3; x++)
bank.add(100);
}
}
public class BankDemo
{
public static void main(String args[])
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
为什么会出现以下的现象
------解决方案--------------------去看看java线程安全
------解决方案--------------------线程同步的问题
public synchronized void add(int n)
{
try
{
Thread.sleep(10);
}
catch (Exception e)
{
}
sum = sum + n;
System.out.println(Thread.currentThread().getName()+"sum="+ sum);
// System.out.println(sum);
}
------解决方案--------------------两个thread中引用的sum都是c.bank.sum,开始的两个100是由于是由于bank被初始化了两次,新手,个人理解
------解决方案--------------------线程问题。得到的结果是随机的。
------解决方案--------------------线程按照:0线程进去运行完sum+n=100,但还没来得及给sum,此时线程1开始运行sum+n,这时sum还是等于0,所以出现Thread-1sum=100,接着线程0恢复,第一次运行完的sum+n=100,给sum,所以输出Thread-0sum=100。后面的就很好理解了,线程1运行=200,线程0运行=300,线程1运行=400,线程0运行=500
------解决方案--------------------你这个奇怪结果也只是一种可能的结果;你多运行几次或修改Thread.sleep(10)的值运行下,也许就有不同的结果;
其实关键是 sum = sum + n; 别看这个只有一条程序语句,实际这里有三条指令:
1、读取sum;
2、sum加n;
3、再赋值sum;
也就是说这个操作不是原子操作;
从上面也就可以知道:为什么会出现两个100
当线程0读取sum为0,再加100,这时线程0中断,线程1读取sum为0,再加100,线程1再中断,线程0赋值sum为100,线程0中断,线程1赋值sum为100,这样就出现了两个100;
至于最终是500,自己可以分析了;
------解决方案--------------------结果是随机的, 你多跑几次就可以发现了.
------解决方案--------------------线程执行是随机的,虽然有的是极少数,但是人一般不会发现它.
------解决方案--------------------很简单啊,你的bank被共享了, sum = sum + n;这里加个同步块就安全了啊
------解决方案--------------------不好意思,要把System.out.println也加到同步块去,这个也不是线程安全的
synchronized (this.getClass()) {
sum = sum + n;
System.out.println(Thread.currentThread().getName()+"sum="+ sum);
}
------解决方案--------------------关于多线程的还应该去理解一下 里面的 锁(synchronized等等)问题···
------解决方案--------------------你的 线程 不安全,关于两个100的问题:当你的一个线程执行的时候,另外一个线程已经读取了 这个线程还没有修改的数据(也就是说,他们读取的数据是一样的),那么他们执行后都打印出来的结果也是一样的,
那个这个时候的数据就是100,然后他们就在100的基础上进行并发执行,,,应该每次运行的结果都有出入,不一样。。
想让他安全,java有synchornized关键字,java1.5后又推出了,lock,这个运用更方便。。建议楼主看看
------解决方案--------------------两个线程都在操作sum变量,执行的顺序是由CPU决定的。加synchornized,可以保证同一时刻只被一个线程用。
------解决方案--------------------楼上都说的很明白了,结贴吧!
------解决方案--------------------你这个奇怪结果也只是一种可能的结果;你多运行几次或修改Thread.sleep(10)的值运行下,也许就有不同的结果;
其实关键是 sum = sum + n; 别看这个只有一条程序语句,实际这里有三条指令:
1、读取sum;
2、sum加n;
3、再赋值sum;
也就是说这个操作不是原子操作;
从上面也就可以知道:为什么会出现两个100
当线程0读取sum为0,再加100,这时线程0中断,线程1读取sum为0,再加100,线程1再中断,线程0赋值sum为100,线程0中断,线程1赋值sum为100,这样就出现了两个100;
至于最终是500,自己可以分析了;
上面的很好的解释
赞一个
------解决方案--------------------由于没有考虑到线程同步问题,可以想象为当两个线程同时执行到这里的时候(几乎同时)sum = sum + n;
当后面的sum+n两个线程都执行之后,然后又同时赋值给sum, 其实是有先后,但是都是在赋值给sum之前执行的,所以就当做同时,所以两个人拿到的值一样。
------解决方案--------------------线程同步安全。还差一步synchronized你就会明白了。。。