Java并发 多线程实现计数功能(线程不安全)

本文介绍了在Java中使用Semaphore、CountDownLatch和newCachedThreadPool实现多线程计数功能,但指出该实现存在线程不安全问题。在并发环境下,计数结果往往无法达到预期的5000,这提示我们需要采用线程安全的方式来改进计数器的实现。

  首先介绍实现改功能的相关名词:Semaphore,CountDownLatch ,newCachedThreadPool

       1.Semaphore


       一个计数信号量。顾名思义,一个信号量拥有一定数量的许可证,一个线程acquire需要申请到许可证才能获取锁,否则阻塞等待;释放的时候会返还许可证给阻塞的线程申请。

        2.CountDownLatch

        CountDownLatch是一个同步的辅助类,它能够使一个线程等待其他线程完成各自的工作后再执行。CountDownLatch是基于AbstractQueuedSynchronizer(AQS)实现的,其通过state作为计数器。构造CountDownLatch时初始化一个state,以后每调用countDown方法一次,state减1;当state=0时,唤醒在await上被挂起的线程。CountDownLatch的计数器state不能被重置,如果需要一种能重置count的版本,可以考虑使用CyclicBarrier。

        3.newCachedThreadPool

        创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程, 那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

 

         4.实现源码:

import com.mmall.concurrency.annoations.NotThreadSafe;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

@NotThreadSafe
public class CountExample {

    //线程并发数量
    private static int threadTotal = 200;
    //请求总数
    private static int clientTotal = 5000;

    private static long count = 0;

    public static void main(String[] args) throws Exception {

        ExecutorService executorService = Executors.newCachedThreadPool();
        //
        final Semaphore semaphore = new Semaphore(threadTotal);
        //每次固定数量的线程获取许可
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int index = 0; index < clientTotal ; index++) {
            executorService.execute(new Runnable() {
                public void run() {
                    try {
                        //获取一个许可
                        semaphore.acquire();
                        add();
                        //释放一个许可
                        semaphore.release();
                    } catch (Exception e) {
                        e.printStackTrace();                  

        }//计数减一
                    countDownLatch.countDown();
                }
            });

       }

          countDownLatch.await();//阻塞当前线程,直到计时器的值为0
           executorService.shutdown();
           System.out.println("finished num : " +count);
    }

    public static void add(){ count++;}

}

      5.运行结果如下:

 

6.结论:从结果看出,几乎每次运行结果都跟实际不相符,都没有达到请求总数5000,说明我们的实现是线程不安全的,下篇我将介绍线程安全的实现方式;。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值