线程安全的定义
一个类是线程安全的 如果他能够在多个线程运行时表现的很正确,不管运行环境那些线程的调度和交织是什么样的 在调用代码里也没有额外的同步和协调措施
无状态sevlet
@ThreadSafe
public class StatelessFactorizer implements Servlet {
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
encodeIntoResponse(req, resp);
}
}
这些变量都是局部变量 是每个线程栈中的局部变量,所以始终是线程安全的
原子性
count++
这个是一个两步的操作,所以不是线程安全的,get and write
竞态条件 延迟初始化
@NotThreadSafe
public class LazyInitRace {
private ExpensiveObject instance = null;
public ExpensiveObject getInstance() {
if (instance == null) {
instance = new ExpensiveObject();
}
return instance;
}
}
这里如果有两个线程的话,线程1判断了是null,进行初始化,但是初始化没有完成,线程2也会认为是null,所以两个都创建了对象
本意是创建一个对象的
复合的行为
检查之后运行和先读后写都是复合行为,操作的动作的序列只有原子的执行时才是线程安全的,可以使用安全类atomic类来保证操作序列的原子性
@ThreadSafe
public class CountingFactorizer implements Servlet {
private final AtomicLong count = new AtomicLong(0);
public long getCount() {return count.get();}
public void service(ServletRequest req, ServletResponse resp) {
BigInteger i = new BigInteger(req);
BigInteger[] factors = factor(i);
count.increamentAndGet();
encodeIntoResponse(resp, factors);
}
}
锁
同步块:
- 需要锁住的对象
- 这个锁保护的代码
synchronized(lock) {
//access or modified shared state guarded lock
}
重入锁
public class Widget {
public synchronized void doSomething() {}
}
public class LoginWidget extends Widget {
public synchronized void doSomething() {}
}
提升性能 尽可能让锁粒度变小
@ThreadSafe
public class CachedFactorizer implements Servlet {
private BigInteger lastNumber;
private BigInteger[] lastFactors;
private long hits;
private long cacheHits;
public synchronized long getHits() {
return hits;
}
public synchronized double getCacheHitsRatio() {
return (double)cacheHits / (double/hits;
}
public void Service(ServletRequest req, ServletResponse reps) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = null;
synchronized(this) {
++ hits;
if (i.equals(lastNumber)) {
++ cacheHits;
factors = lastFactors.clone();
}
}
if (factors == null) {
factors = factor(i);
synchronized(this) {
lastNumber = i;
lastFactors = factors.clone();
}
}
encode(req, reps);
}
}