示例
如果多个线程对同一个共享数据进行访问而不采取同步操作的话,那么操作的结果是不一致的。
以下代码演示了 1000 个线程同时对 cnt 执行自增操作,操作结束之后它的值有可能小于 1000。
public class ThreadUnsafeExample {private int cnt = 0;public void add() {cnt++;}public int get() {return cnt;}public static void main(String[] args) throws InterruptedException {final int threadSize = 1000;ThreadUnsafeExample example = new ThreadUnsafeExample();final CountDownLatch countDownLatch = new CountDownLatch(threadSize);ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100), new ThreadPoolExecutor.CallerRunsPolicy());for (int i = 0; i < threadSize; i++) {executor.execute(() ->{example.add();countDownLatch.countDown();});}countDownLatch.await();executor.shutdown();System.out.println(example.get());}}// 输出结果998 //如果线程是安全的最终结果就是 1000
解决线程安全问题
使用 AtomicInteger
(实际上非阻塞同步)
public class ThreadSafeExample {private AtomicInteger cnt = new AtomicInteger(0);public void add() {cnt.incrementAndGet();}public int get() {return cnt.get();}}
使用 synchronized
(实际上是阻塞同步/互斥同步)
public class ThreadSafeExample {private int cnt = 0;public synchronized void add() {cnt++;}public synchronized int get() {return cnt;}}
使用 Reentrant
(实际上是阻塞同步/互斥同步)
public class ThreadSafeExample {private int cnt = 0;private ReentrantLock lock = new ReentrantLock();public void add() {lock.lock();try {cnt++;} finally {lock.unlock();}}public int get() {lock.lock();try {return cnt;} finally {lock.unlock();}}}
