一、错误示例
static int a = 0; //多线程同时操作 val a
@Test
public void test4() throws InterruptedException {
Runnable runnable = () -> {
while (a < 10) {
a++;
System.out.print(a + "\t");
}
};
Thread t1 = new Thread(runnable);
t1.start(); //线程t1 启动
Thread t2 = new Thread(runnable);
t2.start(); //线程t2 启动
Thread t3 = new Thread(runnable);
t3.start(); //线程t3 启动
}
输出结果: 1 3 4 6 7 8 9 10 2 6
原因:
1.代码可见 我用lambda实现了runnable的实现类
2.下面创建了三个线程分别对同一个runnable变量进行start启动,让jvm去跑这个runnable
这时候三个线程是不同的
但是线程里面有个while条件,注意where条件
a如果小于10,就进循环,然后 a++ 了
这时候我说有bug,你听我细细道来,
假如第一个线程t1 第一次进来a是小于10的…因为第一次a=0
然后t1线程还没有执行到a++的时候t2又进来了
…这时候t1能放过t2吗?
t2给t1说:你管得着吗?你又没有关门,凭什么不让我进来,
这时候t1执行了a++, 但是t1还没有执行输出,t2也执行了a++
输出了:1 (反正不知道是哪个线程输出的)
输出了:3 (我估计是t3线程的干扰)
二、正确示例
static int a = 0; //多线程同时操作 val a
static final Object obj = new Object(); //锁对象
@Test
public void test4() throws InterruptedException {
Runnable runnable = () -> {
synchronized (obj) {
while (a < 10) {
a++;
System.out.print(a + "\t");
}
}
};
Thread t1 = new Thread(runnable);
t1.start(); //线程t1 启动
Thread t2 = new Thread(runnable);
t2.start(); //线程t2 启动
Thread t3 = new Thread(runnable);
t3.start(); //线程t3 启动
}
输出结果: 1 2 3 4 5 6 7 8 9 10
原因:
static final Object obj = new Object();
synchronized (obj) {
}
每个线程执行到synchronized代码块的时候,都会把同一个变量 锁上
因为是static修饰的,所以多个线程都会同意这个锁是同一个锁
因为每个线程进来之前都会去看看这个锁对象有没有被占用
所以实现了分离
t1进来了,其他都进不去,当t1跑完循环,离开了 t2进来了,但是条件不满足了,a已经不小于10了
所以这个正确的结果是同一个线程完成的