@Slf4j
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
// 启动10个线程
ExecutorService threadPool = Executors.newFixedThreadPool(10);
Counter counter = new Counter();
// 同时500000个用户过来请求
for (int i = 1; i <= 500000; i++) {
// threadPool.submit(new Runnable() {
// @Override
// public void run() {
// counter.increment();
// }
// });
threadPool.submit(()->counter.increment());
}
/**
* 将线程池状态置为SHUTDOWN,并不会立即停止:
*/
threadPool.shutdown();
/**
* 当前线程阻塞,等所有已提交线程执行完 如果执行完则返回true 否则返回false
*/
threadPool.awaitTermination(60, TimeUnit.SECONDS);
System.out.println("counter : " + counter.getCount());
}
}
@Slf4j
public class Counter {
int count = 0;
public void increment() {
count = count + 1;
}
public int getCount() {
return count;
}
}
结果
counter.getCount() 结果为 499252 499758 499323 每次运行都产生不一样的结果
为什么不一样
当线程调用increment()方法时,实际上执行了三个步骤
1. 从内存得到count的值
2.将count+1
3.将操作后的值重新存储到内存中
因为是三个步骤所以并不具备原子性
解决方法
使用 synchronized
@Slf4j
public class Counter {
int count = 0;
// 只需要加上synchronized即可
public synchronized void increment() {
count = count + 1;
}
public int getCount() {
return count;
}
}
使用 juc包中的原子类
@Slf4j
public class Counter {
final AtomicInteger count = new AtomicInteger();
// int count = 0; //使用AtomicInteger代替int
public void increment(){
count.getAndIncrement();
//count++; //使用 count.getAndIncrement(); 代替count++
}
public AtomicInteger getCount() {
return count;
}
}
使用ReentrantLock
@Slf4j
public class Counter {
Lock lock = new ReentrantLock();
int count = 0;
public void increment(){
lock.lock();
try{
//业务逻辑处理
count++;
}finally {
lock.unlock(); // 建议在finally处释放锁,以免在运行try{}块时报错,导致最终锁没有释放
}
}
public Integer getCount() {
return count;
}
}
ExecutorService 的 shutdown() shutdownNow() awaitTermination() 详解
shutdown()
将线程池状态置为SHUTDOWN,并不会立即停止:
1.停止接收外部submit的任务
2.内部正在跑的任务和队列里等待的任务,会执行完
3. 等到2完成后,才真正停止
shutdownNow()
将线程池状态置为STOP。企图立即停止,但是并不一定:
1.将shutdown()一样,先停止接收外部提交的任务
2.忽略队列里等待的任务
3.尝试将正在跑的任务interrupt中断
4.返回未执行的任务列表
awaitTermination(long timeOut, TimeUnit unit)
当前线程阻塞
等所有已提交的任务执行完(包括正在跑的和队列中等待的)或者等超时时间到或者线程被中断,抛出InterruptedException
后返回true(shutdown请求后所有任务执行完毕)或false(已超时的任务)
shutdown()和shutdownNow()的区别
shutdownNow()能立即停止线程池,停止所有的任务(包含正在执行的和正在等待的),风险较大
shutdown()只是关闭提交通道,等所有的任务跑完后再停止
shutdown()和awaitTermination()的区别
shutdown()后不能再提交新的任务进去;
awaitTermination()后可以继续提交。
awaitTermination()是阻塞的返回结果是线程池是否已停止(true/false);
shutdown()不阻塞。
总结
优雅的关闭,用shutdown()
立马关闭,并得到未执行任务列表,用shutdownNow()
优雅的关闭,并允许关闭声明后新任务能提交,用awaitTermination()
网友评论