多线程中实例变量的共享造成线程安全问题解决
1. 不共享数据情况
代码实例:
//线程类
public class MyThread1 extends Thread{
private int count = 5;
public MyThread1(String name){
setName(name);
}
@Override
public void run() {
while (count > 0){
count--;
System.out.println("由 " + this.currentThread().getName() +
" 计算, count=" + count);
}
}
}
//测试
//数据不共享
public static void test1(){
MyThread1 MyThread1 = new MyThread1("A");
MyThread1 MyThread2 = new MyThread1("B");
MyThread1 MyThread3 = new MyThread1("C");
MyThread1.start();
MyThread2.start();
MyThread3.start();
}
程序创建了3个线程,每个线程都有自己的count变量,互不干扰,因此变量不共享。
输出结果:

引出问题:如果想多个线程共同操作共享变量,应该怎么操作呢?
2. 共享数据的情况
代码实例:
//线程类
public class MyThread2 extends Thread{
private int count = 5;
@Override
public void run() {
count--;
System.out.println("由 " + this.currentThread().getName() +
" 计算, count=" + count);
}
}
//测试代码,数据共享
public static void test2(){
MyThread2 thread = new MyThread2();
Thread thread1 = new Thread(thread, "A");
Thread thread2 = new Thread(thread, "B");
Thread thread3 = new Thread(thread, "C");
Thread thread4 = new Thread(thread, "D");
Thread thread5 = new Thread(thread, "E");
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
}
线程类中count是共享的,因为值创建了一个MyThread2实例。run方法中不能使用while循环,否则会被单一线程一直做减法处理。
输出结果:

A线程和B线程同时出现3,说明说明A和B同时对count做了处理,产生“非线程安全”问题。想要的结果为依次递减的。
分析:
count–不是一个原子操作,操作分为3步:
- 取得原有count值
- 计算count-1
- 给count赋值
当多线程不能依次获取count值时,就会出现线程安全问题。
解决方法:
在线程类的run方法中添加synchronized关键字,多个线程按序操作,保证为原子操作。
public class MyThread2 extends Thread{
private int count = 5;
@Override
synchronized public void run() {
count--;
System.out.println("由 " + this.currentThread().getName() +
" 计算, count=" + count);
}
}
总结:
- 多线程共享变量使用不当会造成线程安全问题。当出现线程安全问题时,不能保证每个线程对共享变量的操作是原子操作。
- 使用synchronized加在run方法或者使用了共享变量的方法上,执行方法时有效的保证了对共享变量的方法都是原子操作。
本文通过两个实例探讨了多线程环境下线程安全问题的产生与解决方法。首先介绍了不共享数据的情况下各线程独立操作的情形,然后分析了共享数据时因并发操作引发的问题,并提出了使用synchronized关键字来确保操作的原子性。

1761

被折叠的 条评论
为什么被折叠?



