众所周知,在java中有两种方法(或者以上)解决并发的临界资源问题
一种是通过加锁来实现的,即synchronized。
还有一种是ThreadLocal的方法来解决的
但是本人还是对后者有不理解的地方(或者说是什么情况下该用synchronized,什么情况下该用),特此来请教各路大神
同步采用了"以时间换空间的思想",而ThreadLocal采用"以空间换取时间的"思想
public class Chopsticks
{
String name;
private static ThreadLocal enable=new ThreadLocal(){
public Boolean initialValue(){
return true;
}
};
//boolean Enable = true;
public Chopsticks(String name)
{
this.name = name;
}
//synchronized
public boolean pickup(){
if(this.enable.get()==false){
return false;
}
this.enable.set(false);
return true;
// try {
// while(Enable==false) //筷子被用
// {
// this.wait();
// }
// this.Enable =false; //筷子没有被用
// }
// catch (Exception e)
// {
// e.getMessage();
// }
}
public void putdown() {
// this.Enable =true;
// this.notifyAll();
this.enable.set(true);
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class zhexuejia extends Thread
{
String name; //属性
Chopsticks left;
Chopsticks right;
public zhexuejia(String name, Chopsticks l, Chopsticks r) { //初始化
this.name = name;
left = l;
right = r;
}
@Override
public void run() {
left.pickup();
System.out.println(name + " 眼明手快,一把抓起 "+left.name);
right.pickup();
System.out.println(name + " 眼明手快,一把抓起 "+right.name);
System.out.println(name + " 开始进餐");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
System.out.println(name + " 酒足饭饱,打了个饱嗝,心满意足的放下了 "+left.name+" 和 " +right.name);
left.putdown();
right.putdown();
}
public static void main(String []args)
{
Chopsticks k1 = new Chopsticks("1号");
Chopsticks k2 = new Chopsticks("2号");
Chopsticks k3 = new Chopsticks("3号");
Chopsticks k4 = new Chopsticks("4号");
Chopsticks k5 = new Chopsticks("5号");
zhexuejia z1=new zhexuejia("1",k5,k1);
zhexuejia z2=new zhexuejia("2",k1,k2);
zhexuejia z3=new zhexuejia("3",k2,k3);
zhexuejia z4=new zhexuejia("4",k3,k4);
zhexuejia z5=new zhexuejia("5",k4,k5);
ExecutorService e= Executors.newFixedThreadPool(10); //将诸线程加入线程池,并发执行
e.execute(z5);
e.execute(z2);
e.execute(z3);
e.execute(z4);
e.execute(z1);
}
}
执行下来的结果与哲学家就餐的问题不符,问题还是在ThreadLocal的问题上
问题的根源就在于什么情况用锁机制,什么情况用ThreadLocal的机制
Spring中的源代码大量使用了ThreadLocal来保持同步,不知道这种同步和哲学家就餐有什么不同呢?
疑问
我们来看下ThreadLocal的使用场景:
ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。
每个线程访问的都是该线程对该对象的副本或者copy(各个线程运行自己的,彼此之间并不进行数据共享或通过该对象进行线程通信),并不修改原始对象,在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。 如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。
你所给的代码中,你的本意是用enable来担任synchronized的锁的角色,希望用enable来控制各个线程的调用,也就是说它是一个共享对象,完全不适应ThreadLocal的场景,你应该用synchronized的。