最近想了解并发编程,二线程安全是它的基础。所以看了下java相关的线程安全知识。
线程安全的核心是代码正确性(一般是输出的结果);
首先无状态的对象是线程安全的;因为一个无状态的对象即不包含其他域;也没有对其他域的引用;
(1)原子性
原子性:即代码不可在分割;例如 a=0;中间没有其他操作。a++则不是他要先赋值a再执行加法操作。
不是原子性操作的代码可能会因为时序或多线程操作等等原因导致缓存中的对象不是正确的结果。
java提供了锁机制来保证代码块的原子性。synchronized关键字。 线程在进入修饰由该关键字修饰的代码块之前就自动获得一个锁,退出时释放该锁。当有一个线程持有这种锁的时候,其他线程就必须等待或阻塞。直到持有线程释放。但这带来了性能较慢的问题。
同时java也提供了重入机制:同一线程可再次进入锁如下
public class Father {
public synchronized void doing(){
System.out.println(toString() + ": father doing");
}
}<pre name="code" class="java">public class Children extends Father{
public synchronized void doing(){
System.out.println(toString() + ": son doing");
super.doing();
}
public static void main(String[] args) {
Children children = new Children();
children.doing();
}
}
结果如下:
Children@cfd22a: son doing
Children@cfd22a: father doing
表明锁是可以重新进入的。而且jvm实际上给每进入一次锁就会在计数值上加1。退出减一。0表示没锁定。这种方式提升了封装性。
我们对于有多个变量的不变性条件,一般这些变量共用一个锁。
关于锁与性能:我们对于时间较长的操作:如网络I/O或控制台I/O,一定不要持有锁。同时s锁控制的代码块尽量要小。