Java多线程共享资源
程序员文章站
2024-02-17 17:36:22
...
多线程中的一个核心问题就是对共享资源的读写问题。你永远都不知道一个线程何时在运行。如果同时有多个线程对一个对象进行读写,结果就会出现脏数据
接下来展示一个多线程同时对一个对象进行读写出现脏数据的案例。
为了方便解耦,创建一个抽象类。
public abstract class Ingenerator {
private volatile boolean caceled = false;
public abstract int next();
public void cacel(){
caceled = true;
}
public boolean isCanceled(){
return caceled;
}
}
EvenChecker任务总是读取和测试从其相关的Ingenerator 返回的值。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class EvenChecker implements Runnable {
private Ingenerator generator;
public EvenChecker(Ingenerator g){
generator = g;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(!generator.isCanceled()){
int val = generator.next();
if(val%2!=0){
System.out.println(val + " not even!");
generator.cacel();
}
}
}
public static void test(Ingenerator gp,int count){
System.out.println("Press Control to exit");
ExecutorService exec = Executors.newCachedThreadPool();
for(int i = 0;i<count;i++){
exec.execute(new EvenChecker(gp));
}
exec.shutdown();
}
}
继承Ingenerator抽象类的next()产生偶数。
public class EvenGenerator extends Ingenerator {
private int currentEvenValue = 0;
@Override
public int next() {
++currentEvenValue;
++currentEvenValue;
return currentEvenValue;
}
public static void main(String[] args) {
EvenChecker.test(new EvenGenerator(), 10);
}
}
一个线程有可能在另一个线程执行第一个++currentEvenValuede 操作之后,还没有来得及执行第二个操作之前调用了next()方法。这个时候可能就会产生一个奇数。也就是脏数据。
基本上所有的并发模式在解决线程冲突问题的时候,都是采用序列化访问共享资源的方案。
一个屋子只有一个浴室,多个人(多个线程)都希望能单独使用这个浴室(共享资源)。为了使用浴室,一个人先敲门,看看有没有人,如果没人的话,他就进入浴室并锁上门。等待使用浴室的人们挤在浴室门口,当锁住浴室门的那个人打开锁离开的时候,离门最近的那个人可能进入浴室,可以通过yield()和setPriority()来给线程调度器提供建议,虽然未必有用。还是取决于CPU。
Java提供关键字synchronized的形式,来防止资源冲突。当线程执行被synchronized关键字保护的代码片段时,它将检查锁是否可用,然后获取锁,执行代码,释放锁。
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:492139965 我们一起学Java!