Java使用代码模拟高并发操作的示例

 更新时间:2018年05月04日 10:35:55   作者:Oo若离oO  
本篇文章主要介绍了Java使用代码模拟高并发操作的示例,Java通过代码模拟高并发可以以最快的方式发现我们系统中潜在的线程安全性问题,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

在java中,使用了synchronized关键字和Lock锁实现了资源的并发访问控制,在同一时间只允许唯一了线程进入临界区访问资源(读锁除外),这样子控制的主要目的是为了解决多个线程并发同一资源造成的数据不一致的问题。在另外一种场景下,一个资源有多个副本可供同时使用,比如打印机房有多个打印机、厕所有多个坑可供同时使用,这种情况下,Java提供了另外的并发访问控制--资源的多副本的并发访问控制,今天使用的Semaphore即是其中的一种。

Java通过代码模拟高并发可以以最快的方式发现我们系统中潜在的线程安全性问题,此处使用Semaphore(信号量)和 CountDownLatch(闭锁)搭配ExecutorService(线程池)来进行模拟,主要介绍如下:

1、Semaphore

JDK 1.5之后会提供这个类

Semaphore是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。

2、CountDownLatch

 JDK 1.5之后会提供这个类,

CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。

如下图:

以上两个类可以搭配使用,达到模拟高并发的效果,以下使用代码的形式进行举例:

package modules;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class CountExample {
  // 请求总数
  public static int clientTotal = 5000;
  // 同时并发执行的线程数
  public static int threadTotal = 200;
  public static int 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 i = 0; i < clientTotal ; i++) {
      executorService.execute(() -> {
        try {
         //执行此方法用于获取执行许可,当总计未释放的许可数不超过200时,
         //允许通行,否则线程阻塞等待,直到获取到许可。
          semaphore.acquire();
          add();
          //释放许可
          semaphore.release();
        } catch (Exception e) {
          //log.error("exception", e);
          e.printStackTrace();
        }
        //闭锁减一
        countDownLatch.countDown();
      });
    }
    countDownLatch.await();//线程阻塞,直到闭锁值为0时,阻塞才释放,继续往下执行
    executorService.shutdown();
    log.info("count:{}", count);
  }
  private static void add() {
    count++;
  }
}

如上方法模拟5000次请求,同时最大200个并发操作,观察最后的结果,发现每次的结果都有差别,和预期不符,得出结果部分如下:

22:18:26.449 [main] INFO modules.CountExample - count:4997
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:4995
22:18:26.449 [main] INFO modules.CountExample - count:4998

最后结论:add 方法 非线程安全

那如何保证add方法 线程安全,将add方法进行如下修改即可:

private static void add() {
   count.incrementAndGet();
}

执行结果如下:

22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000

最后结论:修改后 的  add 方法 线程安全

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 使用Spring事物时不生效的场景及解决方法

    使用Spring事物时不生效的场景及解决方法

    今天介绍一下Spring事物不生效的场景,事物是我们在项目中经常使用的,如果是Java的话,基本上都使用Spring的事物,不过Spring的事物如果使用不当,那么就会导致事物失效或者不回滚,最终导致数据不一致,下面我们意义列举不生效的场景,并给出解决方法
    2023-09-09
  • Java给PDF加水印并合并多个文件

    Java给PDF加水印并合并多个文件

    大家好,本篇文章主要讲的是Java给PDF加水印并合并多个文件,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-02-02
  • Java C++题解leetcode672灯泡开关示例

    Java C++题解leetcode672灯泡开关示例

    这篇文章主要为大家介绍了Java C++题解leetcode672灯泡开关示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • 自定义的Troop<T>泛型类( c++, java和c#)的实现代码

    自定义的Troop<T>泛型类( c++, java和c#)的实现代码

    这篇文章主要介绍了自定义的Troop<T>泛型类( c++, java和c#)的实现代码的相关资料,需要的朋友可以参考下
    2017-05-05
  • Java使用Sharding-JDBC分库分表进行操作

    Java使用Sharding-JDBC分库分表进行操作

    Sharding-JDBC 是无侵入式的 MySQL 分库分表操作工具,本文主要介绍了Java使用Sharding-JDBC分库分表进行操作,感兴趣的可以了解一下
    2021-08-08
  • java分布式面试接口如何保证幂等及概念理解

    java分布式面试接口如何保证幂等及概念理解

    这篇文章主要为大家介绍了java分布式面试中接口如何保证幂等的问题解答以及概念描述,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-03-03
  • Java内建函数与库的最佳实践方式

    Java内建函数与库的最佳实践方式

    Java提供了许多高效的内建函数和库,如Math、String、Arrays、Collections等类,以及java.util.concurrent、java.nio、java.util.stream、java.util.regex和java.time等包,通过利用这些工具和方法,可以显著提高Java代码的性能和效率
    2025-03-03
  • Mybatis引入与使用的图文步骤

    Mybatis引入与使用的图文步骤

    本文主要介绍了Mybatis引入与使用的图文步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • java设计模式之工厂方法模式

    java设计模式之工厂方法模式

    这篇文章主要为大家详细介绍了java设计模式之工厂方法模式,什么是java工厂方法模式,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • struts2实现简单文件下载功能

    struts2实现简单文件下载功能

    这篇文章主要为大家详细介绍了struts2实现简单文件下载功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01

最新评论