标签:
hidden mutable state和escaped state是两种线程不安全问题:两者原因不同,前者主要是由于类成员变量中含有其他对象的引用,而这个引用是immutable的;后者是成员方法的返回结果类型需要注意,否者都会引起线程安全问题
1、关于hidden mutable state问题:
注意成员变量如果是另一个对象的引用情况
这个问题简而言之就是说一个类的成员变量有可能是暗含状态的,就是说成员是一个对象的引用哪个对象是有状态的,虽然这个引用可能定义为final不可变的但依然不是线程安全的!
首先说明一个类的实例 如何被多线程程序执行?
public class DateFormatTest {
//这里说明成员变量的初始化会在构造函数之前进行!!
private final DateFormat format =new SimpleDateFormat("yyyyMMdd");
public Date convert(String source) throws ParseException{
Date d = format.parse(source);
return d;
}
}// 成员变量是immutable,又不提供方法改变这个成员,这个对象是immutable?no,因为成员变量DateFormat的问题
//定义一个对象然后被多线程共用
final DateFormatTest t = new DateFormatTest();
Callable<Date> task = new Callable<Date>(){
public Date call() throws Exception {
return t.convert("20100811");
}
};
//lets try 2 threads only
ExecutorService exec = Executors.newFixedThreadPool(2);
List<Future<Date>> results =new ArrayList<Future<Date>>();
//perform 5 date conversions
for(int i = 0 ; i < 5 ; i++){
results.add(exec.submit(task));
}
exec.shutdown();
//look at the results
for(Future<Date> result : results){
System.out.println(result.get());
}
》》0.1、说明下这个类
This code is not thread safe because SimpleDateFormat.format is not.Is this object immutable? Good question! We have done our best to make all fields not modifiable, we don‘t use any setter or any methods that let us suggest that the state of the object will change. Actually, internally SimpleDateFormat changes its state, and that‘s what makes it non-thread safe. Since something changed in the object graph, I would say that it‘s not immutable, even if it looks like it...
>>0.2、hidden mutable state问题
SimpleDateFormat
这个类的实例对象中保存有 intermediate results,所以如果一个实例对象被多个线程执行就可能会混淆彼此的执行结果。----该类有成员变量
class SimpleDateFormat
{
private Calendar
calendar
;
….
public void parse(){
calendar.clear();//
清空
calendar.add(..);//
填充
}
}
SimpleDateFormat
stores intermediate results in instance fields. So if one instance is used by two threads they can mess each other‘s results.
Looking at the source code reveals that there is a Calendar
instance field, which is used by operations on DateFormat
/ SimpleDateFormat
For example parse(..)
calls calendar.clear()
initially and then calendar.add(..)
. If another thread invokes parse(..)
before the completion of the first invocation, it will clear the calendar, but the other invocation will expect it to be populated with (被填充)intermediate results of the calculation.
One way to reuse date formats without trading thread-safety is to put them in a ThreadLocal
- some libraries do that. That‘s if you need to use the same format multiple times within one thread. But in case you are using a servlet container (that has a thread pool), remember to clean the thread-local after you finish.
>>0.3、解决办法可以做thread local
Another approach is to use a ThreadLocal variable to hold the DateFormat object,
which means that each thread will have its own copy and doesn‘t need to wait
for other threads to release it. This is generally more efficient than
synchronising sa in the previous approach.
public class DateFormatTest {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyyMMdd"); } };
public Date convert(String source) throws ParseException{ Date d = df.get().parse(source); return d; } } |
》》2、关于escaped state问题:
注意函数的返回结果!!!
public class Tournament {
private List<Player> players = new LinkedList<Player>();
public synchronized void addPlayer(Player p) {
players.add(p);
}
public synchronized Iterator<Player> getPlayerIterator() {
return players.iterator();
}
}比如该类成员的所有操作都是synchronize方法做的,成员是可变的,但是也不是线程安全的!
要考虑每个方法返回的结果是否依旧可以操纵这个对象的可变状态!
问题在于:函数getPlayerIterator() 的返回结果iterator still references the mutable state contained within players—if another thread calls addPlayer() while the iterator is in use
两种线程不安全escaped state以及hidden mutable
标签:
原文地址:http://www.cnblogs.com/amazement/p/4866325.html