以前也算是看过并发编程实战这本书。但是一直做的是书中的笔记。如今从头看此书。希望把笔记记录成博客。以便以后查询。
- 怎么确定一个类是线程安全的:
当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要添加额外的同步或者协同。这个类都能表现出正确的行为,那么就称这个类是线程安全的。
2.2.1:无状态对象一定是线程安全的
在本书中描述是:既不包含任何域,也不包含任何对其它类中域的引用。
在没有同步的情况下统计已处理请求数量的Servlet(不要这么做)
public class UnsafeCountingFactorizer implements Servlet {
private long count = 0;
public long getCount() {
return count;
}
@Override
public void service(ServletRequest request, ServletResponse response){
BigInteger i = extraactFromeRequest(request);
BigInteger[] factors = factor(i);
++count;
encodeIntoResponse(response, factors);
}
}
UnsafeContingFactorizer是非线程安全的。当多个线程访问时候,count在进行++count时,就会产生:竞态条件。 ++count在JVM中他的执行过程是 读取-修改-写入。多个线程对count进行++操作时候,就可能会产生多个线程读取的是同一个值,修改后的值一直,导致统计不准确。
2.2.2
延迟初始化中的竟态条件:
最常见的就是我们在单例模式中,我们可以采取延迟初始化而避免线程不安全。当然下面代码是线程不安全的。是一个错误示例:
//这个是线程不安全的。只是示例延迟初始化也会产生竟态条件
public class LazyInitRace {
private LazyInitRace lazyInitRace ;
private LazyInitRace(){};
public LazyInitRace getInstance() {
if(lazyInitRace == null) {
lazyInitRace = new LazyInitRace();
}
return lazyInitRace;
}
}
2.2.3 复合操作
包含一组必须以原子方式执行的操作我们称之为符合操作。如:延迟初始化、读取-修改-写入。
我们有时候可以采取原子变量类。java.util.concurrent.atomic中的原子变量类来保证线程安全性
public class UnsafeCountingFactorizer implements Servlet {
private final AtomicLong count = new AtomicLong(0);
public long getCount() {
return count.get();
}
@Override
public void service(ServletRequest request, ServletResponse response){
BigInteger i = extraactFromeRequest(request);
BigInteger[] factors = factor(i);
count.incrementAndGet();
encodeIntoResponse(response, factors);
}
}
这样就可以解决线程安全性问题。当然对于java.utilconcurrent包下面的类会在后续读到的时候进行想写的记录。也会对源码进行分析记录。
2.3 锁
2.3.1:Java提供了一种内置的锁机制来支持原子性——同步代码块(Synchronized Block).被Synchronized 修饰的普通方法的锁就是方法调用所在的对象。简单讲就是对象锁。静态的Synchronized方法是一Class对象作为锁。也就是类锁。Java的内置锁是一种互斥锁:也就是说最多只有一个线程能持有这种锁。
2.3.2:重入:java内置锁是可以重入的。如果某个线程试图获取自己已经拥有的锁,那么这个请求就会成功。 “重入” 意味着获取锁的操作粒度是线程,而不是调用。
//内置锁可重入,就不会让这样的代码发生死锁。
public class Widget {
public synchronized void doSomething() {
...........
}
public class loggingWidget extends doSomething() {
public synchronized void doSomething() {
...........
super.doSomethin();
}
}
}