这节课我们来学习下多线程可能引发的问题以及解决方法
先来看一个小例子:
public class MultiThreadDemo {
public static void main(String[] args) {
DemoRunnable demoRunnable = new DemoRunnable();
//创建两个线程
Thread thread1 = new Thread(demoRunnable);
Thread thread2 = new Thread(demoRunnable);
//启动线程
thread1.start();
thread2.start();
//等两个线程停止后,输出demoRunnable.i
while (true)
{
if (thread1.getState() == Thread.State.TERMINATED && thread2.getState() == Thread.State.TERMINATED)
{
System.out.println(demoRunnable.i);
break;
}
}
/**
* 各位来猜下结果是多少?
*
* 按常理来讲是200对吧,来看看结果,完美,但这并不是我想要的结果
* 这样改了之后就应该是4000了对吧,没有问题
*
* 继续增大后应该是8000了对吧,出问题了
*
* 输出结果:
* 第一次: 7477
* 第二次: 8000
* 第三次: 5788
* 第四次: 5299
*
* 可以看到每一次输出结果都不一样,大家也可以自己在下面试试,接下来就讲下为什么会这样。
*/
}
}
class DemoRunnable implements Runnable{
public int i;
@Override
public void run() {
for (int j = 0; j < 4000; j++) {
i++;
}
}
}
接下来进入今天的主题:
主题一: 多线程引发的问题
当多个线程操作同一块内存时可能导致该内存数据最后得不到正确的数据(或者说我们想要的数据)
为什么呢?这个就得说下java里的原子性操作了。
原子操作: 指不可分割的操作(百度百科说的好麻烦,就记住原子操作不可分割就可以了)
Java中的原子操作包括:
1)除long和double之外的基本类型的赋值操作
2)所有引用reference的赋值操作
3)java.concurrent.Atomic.* 包中所有类的一切操作
i++不是原子操作
i++可以被分割为三个步骤:
- tmp = i(将i的值取出来存放到一个临时变量tmp中)
- tmp = tmp + 1(tmp自增1)
- i = tmp (将tmp的值回到i中)
为什么多线程在操作同一块内存的时候会出现问题呢?画图
总共执行了两次i++,但最终i的值却为1
这就是多线程可能引发的问题
解决方案: 给共享变量加同步锁,关键字是synchronized
下节课细讲synchronized同步锁