请问为什么会出现这样的执行结果?两个线程同时执行,同时拿到了count = 8我能理解,但如果两个线程都执行了count++,为什么结果不是10?难道是 count = count + 1,两者都拿到了 8,+1之后两者又都更新为9,这整个执行过程中有什么细节吗?这个静态变量在多线程中有什么说法?
public class Test02 implements Runnable {
private static int count;
public Test02() {
count = 0;
}
public void run() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public int getCount() {
return count;
}
public static void main(String[] args) {
Thread thread1 = new Thread(new Test02(), "SyncThread1");
Thread thread2 = new Thread(new Test02(), "SyncThread2");
thread1.start();
thread2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(test02.getCount());
}
}
用互斥锁
你这同步用的 是 this,也就是当前的 实现Runnable接口的Test02的实例对象;
你创建了两个线程,分别new Test02(); 那相当于两个线程进来都是 不同的 实例对象,所以你的 synchronized(this) 同步了个寂寞
像你这样将同步放到for循环外面,如果同步是有用的, 要等到一个线程执行完了,其他线程才能执行。
给你个示例,可以实现 交替执行两个线程,
先看截图:
参考如下:
public class Test02 implements Runnable {
private static Object obj = new Object();
private static int count = 0;
public void run() {
for (int i = 0; i < 5; i++) {
try {
synchronized (obj) {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
}
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread thread1 = new Thread(new Test02(), "SyncThread1");
Thread thread2 = new Thread(new Test02(), "SyncThread2");
thread1.start();
thread2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Test02.count);
}
}
public class Counter{
private int count;
public void increase(){
count++;
}
问题
该代码可能在多线程条件下出现问题,因为count++是非原子的。
count++ 实际上等于三个操作:读数据,加1,写回数据。
解决
为了防止多线程下访问increase方法会报错,所以给increase方法加锁。
count变量修改了其他线程可能看不到,所以就加个volatile关键字吧。
首先,问题中的现象是因为count++操作不是原子操作,而是由读取、增加和赋值三个操作组成的。当两个线程同时执行count++的时候,两个线程先后读取count的值,然后同时进行增加操作,最后赋值给count。因为两个线程同时读取的值都是8,所以最终只有一个线程的增加操作生效,另一个线程的增加操作则被覆盖,导致最终的结果是9而不是10。
解决这个问题可以采用以下两种方案:
方案1:使用synchronized关键字加锁
public class Increment {
private static int count = 8;
public static synchronized void increase() {
count++;
}
}
在这个方案中,使用synchronized关键字修饰increase()方法,保证同一时间只有一个线程能够执行该方法,避免了多个线程同时操作的问题。
方案2:使用AtomicInteger类
import java.util.concurrent.atomic.AtomicInteger;
public class Increment {
private static AtomicInteger count = new AtomicInteger(8);
public static void increase() {
count.incrementAndGet();
}
}
在这个方案中,使用AtomicInteger类代替int类型的count变量,AtomicInteger类提供了原子操作的方法,包括incrementAndGet()方法用于增加操作,保证了多个线程同时操作的线程安全。
需要注意的是,使用synchronized关键字会引入锁的开销,可能会影响性能。而使用AtomicInteger类可以更高效地实现线程安全的自增操作。
对于多线程中对静态变量的操作,需要注意以下几点:
静态变量是被所有对象所共享的,所以在多线程环境下可能会有竞争条件的问题,需要保证对静态变量的操作是线程安全的。
如果需要对静态变量进行自增等操作,应该使用原子类或者加锁来保证线程安全。
如果静态变量是可变对象,需要注意在多线程环境下的同步问题,比如使用synchronized关键字或者使用线程安全的数据结构。