前段时间,因为出了一个貌似和多线程有关的问题(最后证明又不是)。我好好的看了下一些多线程的资料。做下简单的总结免得以后搞忘了。
1。多线程产生原因。一是GUI,二是效率
2。处理多线程中,最重要的问题就是资源抢占问题。
解决思路有2个:a.上锁 b.让资源不被争抢
a.在java里面就是synchronize 或者新的Lock对象(Java5以后).synchronize 方法被调用时,直接会把当前对象锁了,在方法执行完之前其他线程无法调用当前对象的其他方法。所以synchronize的方法尽量小,做不到很小就synchronize一个区块。
b.就是ThreadLocal,ThreadLocal是线程独立的资源,如ThreadLocal<Integer> 那么每个线程都可以任意修改而互不影响.
它并不是一个Thread,而是thread local variable
具体看ThreadLocal的源码就了了,很简单
public class ThreadLocal
{
private Map values = Collections.synchronizedMap(new HashMap());
public Object get()
{
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread))
{
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue)
{
values.put(Thread.currentThread(), newValue);
}
public Object initialValue()
{
return null;
}
}
3.关于wait notify 老式同步方法。首先呢,写起来烦,代码绝对绝对高耦合,再之新的concurrency 包里有很多有用的同步类比如BlockingQueue
4.尽量不要直接用.start()起线程,而用Executor来管理。原因 1.多线程环境下如果有异常会直接飞出你的控制,当然有办法。2.就是随便.start()线程,可能会让线程所在对象在要使用的时候处于不完整状态。
关于如何多线程抓异常,thining in java 4th p1149有说,就是实现个ThreadFactory接口,然后把异常捕获器设给新开的线程,然后把实现了ThreadFactory的工厂给Executor 就O 了。
5.关于volatile,就是强制读类存数据,无视寄存器。不过即便这样,操作volatile类变量的时候仍然要加锁。
6.关于什么可以说是默认线程安全的。不安全的有 所有长度超过32位的读因为要读两次。
然后就是其他语言基本都是线程安全的自增比如
class A{
int i;
void f1(){i++;}
}
反编译出来结果:
aload_0
dup
getfield
iconst_1
iadd
putfield
return
读和+中间可能会产生CPU上下文切换,这个时候值肯能被改。
7.小技巧。//NOT thread safe
while(conditionXXXX){
//conditionXXXX could be changed here
synchonized(this){
//dosomething
}
}
//safe
synchonized(this){
while(conditionXXXX){
//dosomething
}
}