一、背景介绍
今天在使用synchronized关键字修饰变量进行多线程操作的时候,idea突然有个黄色的提示,直译过来的意思就是在非最终字段count上同步。
二、错误代码
public class Demo1 {
static Integer count = 0;
@SneakyThrows
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
synchronized (count){
count++;
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
synchronized (count){
count--;
}
}
}
});
t1.start();
t2.start();
// 主线程等待t1和t2执行完成,再执行下面的代码
t1.join();
t2.join();
System.out.println(count);
}
}
代码执行得到的结果任然不为0
三、为什么加了synchronized锁,锁住资源之后,进行线程操作,还是会有并发问题?
原因在于最开始的那段警告,因为加锁在了非最终字段上,所谓非最终字段,即这个字段的引用地址值是会发生改变的。而synchronized关键字在多个线程之间想要完成串行操作,要求锁住的资源一定是同一个,而上述的非最终同步字段就打破了这个要求。所以造成了锁的失效,因此我们只需要将锁资源换成一个不会改变地址值的对象即可
四、正确代码
public class Demo1 {
static Integer count = 0;
static Object lock = new Object();
@SneakyThrows
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
synchronized (lock){
count++;
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5000; i++) {
synchronized (lock){
count--;
}
}
}
});
t1.start();
t2.start();
// 主线程等待t1和t2执行完成,再执行下面的代码
t1.join();
t2.join();
System.out.println(count);
}
}