多线程的并发安全
问题:统计某接口访问次数
//错误示例
public class AccessCounter {
/**
* 访问接口的次数
*/
int count;
public void access(){
count++;
}
}
接口很可能被多个线程同时访问,即access()方法被多个线程调用
解决方案
1.无锁
- 用局部变量可以避免出现线程安全问题
- 定义不可变对象,如String类型
ThreadLocal:
每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题
- CAS原子类:
* 在Java中的实现则通常是指以英文Atomic为前缀的一系列类,它们都采用了CAS的思想。
* Atomic系列的使用的是一种无锁化的CAS操作,是基于乐观锁的,它的并发性能比较高,可以多个线程同时执行,并且保证不会出现线程安全问题。
public class AccessCounter {
/**
* 访问接口的次数
*/
AtomicInteger count = new AtomicInteger(0);
public void access(){
count.incrementAndGet();
System.out.println("访问次数:"+count.get());
}
}
2.加锁
- Synchronized加锁/ReentrantLock加锁
public class Counter {
int i = 0;
ReentrantLock lock = new ReentrantLock();
/**
* ReentrantLock加锁
*/
public void lock1(){
lock.lock();
try {
add();
}finally {
lock.unlock();
}
}
/**
* synchronized加锁
*/
public synchronized void lock2(){
add();
}
void add(){
i++;
}
}