package threading;
//线程安全
class Counter{
public int count = 0;
public void increase(){
count++;
}
}
public class Demo14 {
//每个线程自增5W次
public static Counter counter = new Counter();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
Thread t2 = new Thread(()->{
for (int i = 0; i < 50000; i++) {
counter.increase();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("counter: "+counter.count);
}
}
上述代码是创建两个线程,每个线程通过counter来进行5w次自增。最后预期的结果肯定是10w
运行后可以发现:每一次运行的结果都不一样。此时bug就出现了。
出现的bug原因如下:
进行的 count ++ 操作,底层是三条 指令 在 CPU 上完成的!!!
1)把内存的数据读取到 CPU 寄存器中 load
2)把 CPU 的寄存器中的值,进行 +1 add
3)把寄存器中的值,写回到内存中 save
因为并发的关系,线程之间的调度顺序不确定,而且是两个线程修改一个变量。
所以两个线程执行这些操作时就可能有多种执行的顺序。
(这两种排列顺序说没问题的)
等等等等等
除了前两种”串行执行“的情况,其他都是有问题的!
那第三个排序方法举个例子:
本来count=2的它给搞个1,这就说明有bug了。所以,有不确定的值。
那
如何解决嘞
这就要用到加锁的操作,把count++变成原子的(不会被线程调度机制打断的操作:跟原子一样,不可分嘛~):
在count++之前加锁,count++执行之后再解锁。
在加锁和解锁之间,进行修改,这个时候别的线程想要修改,不好意思,修改不了!!
(别的线程只能阻塞等待,阻塞等待的线程状态,BLOCKED 状态)
Java中,进行加锁,使用synchronized(读:心抠奈字的)
这样运行就是10_0000啦!
当然,synchronized也可以修饰代码块。
synchronized()里面填的东西就是你要针对那个对象加锁(锁对象)我这里用this就以为这谁调用increase方法谁就是this。