Java Semaphore实现高并发场景下的流量控制

目录
  • 前言
  • Semaphore介绍
  • 代码演示
  • 补充
    • 独占锁与共享锁
    • 公平锁与非公平锁
    • 可重入锁

前言

在java开发的工作中是否会出现这样的场景,你需要实现一些异步运行的任务,该任务可能存在消耗大量内存的情况,所以需要对任务进行并发控制。如何优雅的实现并发控制呢?下面我会给大家介绍一个类——Semaphore,能很优雅的实现并发控制,继续往下看吧。

Semaphore介绍

首先我们看一下Semaphore类的构造函数是如何实现的。

    public Semaphore(int permits, boolean fair) {
        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
    }

我们可以看到有两个参数,分别对应的是信号量的许可次数以及是否为公平锁,其中关于锁的概念可以参考补充。

我们看一下主要使用到的方法——tryAcquire,尝试申请锁,看一下该方法有几个实现。

    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }
    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
    public boolean tryAcquire(int permits) {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.nonfairTryAcquireShared(permits) >= 0;
    }
    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
    }

我们需要注意的是,Semaphore是一个可重入的共享锁,所以除了可以增加申请锁的超时时间外,还可以设置申请的许可证数量。一般在业务场景中申请1次就可以了。

Semaphore还提供了阻塞的申请方式,一旦执行就会一直阻塞直到申请到锁,就是acquire方法。有兴趣的话,可以看看,也基本上支持多种参数实现。

代码演示

下面看一下我写的demo代码,演示一下Semaphore的限流效果。

先添加一些maven依赖

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.15</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

示例代码

package com.huyi.csdn.tools;

import cn.hutool.core.thread.ThreadUtil;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

/**
 * @Program: csdn @ClassName: SemaphoreDemo @Author: 剑客阿良_ALiang @Date: 2021-12-18
 * 10:03 @Description: @Version: V1.0
 */
@Slf4j
public class SemaphoreDemo {
  private static final Semaphore SEMAPHORE = new Semaphore(3, true);
  private static final ExecutorService POOL =
      Executors.newFixedThreadPool(10, new CustomizableThreadFactory("TASK-"));
  private static final ScheduledExecutorService ENGINE_POOL =
      Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("ENGINE-"));
  public static LinkedBlockingQueue<Task> taskQueue;
  public static AtomicInteger codeBuilder;

  @Data
  @Builder
  public static class Task {
    private Integer code;
    private Runnable work;
  }

  public static void init() {
    taskQueue = new LinkedBlockingQueue<>();
    codeBuilder = new AtomicInteger(0);
    log.info(">>> 任务队列初始化");
    log.info(">>> 任务引擎启动");
    engineOn();
  }

  private static void engineOn() {
    ENGINE_POOL.scheduleAtFixedRate(
        () -> {
          if (taskQueue.isEmpty()) {
            log.info("队列为空,无任务需要执行");
          } else {
            if (SEMAPHORE.tryAcquire()) {
              try {
                Task task = taskQueue.poll();
                log.info("code:{} 任务获得执行许可", task.getCode());
                POOL.submit(task.getWork());
                log.info("code:{} 任务提交执行", task.getCode());
              } catch (Exception exception) {
                exception.printStackTrace();
              }
            } else {
              log.info("执行任务数量已经达到限制,无法执行任务");
            }
          }
        },
        0,
        1,
        TimeUnit.SECONDS);
  }

  public static void addTask(Runnable runnable) {
    Integer code = codeBuilder.incrementAndGet();
    Task task =
        Task.builder()
            .code(code)
            .work(
                () -> {
                  try {
                    runnable.run();
                  } catch (Exception exception) {
                    exception.printStackTrace();
                  } finally {
                    log.info("code:{}-结束任务", code);
                    SEMAPHORE.release();
                  }
                })
            .build();
    taskQueue.add(task);
  }

  public static void main(String[] args) {
    SemaphoreDemo.init();
    Random random = new Random();
    for (int i = 0; i < 10; i++) {
      SemaphoreDemo.addTask(
          () -> {
            IntStream.range(1, random.nextInt(10) + 1)
                .forEach(
                    a -> {
                      log.info("第{}次进攻敌方基地", a);
                      ThreadUtil.sleep(1000);
                    });
            log.info("进攻结束");
          });
    }
  }
}

代码说明:

1、先添加了两个静态的线程池,一个为给引擎工作的定时线程池,一个为给异步任务提供的任务线程池。

2、在初始化的时候会提前创建好任务队列,这里使用的是LinkedBlockingQueue。

3、初始化之后,可以引擎会定时尝试获取Semaphore的许可证,如果可以拿到则将任务提交给线程池执行。

4、在构建任务的时候,会将需要执行的内容重新包装,保证任务执行结束的时候会主动释放Semaphore的许可证。

5、main方法主要是在10秒内提交10个不定时完成的任务,我们可以看看是否限制了异步任务的数量。

验证一下,看看执行结果

E:\Java\jdk1.8.0_40\bin\java.exe "-javaagent:E:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\lib\idea_rt.jar=3927:E:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\bin" -Dfile.encoding=UTF-8 -classpath E:\Java\jdk1.8.0_40\jre\lib\charsets.jar;E:\Java\jdk1.8.0_40\jre\lib\deploy.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\dnsns.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\jaccess.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\localedata.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\nashorn.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\sunec.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;E:\Java\jdk1.8.0_40\jre\lib\ext\zipfs.jar;E:\Java\jdk1.8.0_40\jre\lib\javaws.jar;E:\Java\jdk1.8.0_40\jre\lib\jce.jar;E:\Java\jdk1.8.0_40\jre\lib\jfr.jar;E:\Java\jdk1.8.0_40\jre\lib\jfxswt.jar;E:\Java\jdk1.8.0_40\jre\lib\jsse.jar;E:\Java\jdk1.8.0_40\jre\lib\management-agent.jar;E:\Java\jdk1.8.0_40\jre\lib\plugin.jar;E:\Java\jdk1.8.0_40\jre\lib\resources.jar;E:\Java\jdk1.8.0_40\jre\lib\rt.jar;C:\Users\yi\IdeaProjects\csdn\target\classes;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.5.6\spring-boot-starter-web-2.5.6.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-starter\2.5.6\spring-boot-starter-2.5.6.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.5.6\spring-boot-starter-logging-2.5.6.jar;C:\Users\yi\.m2\repository\ch\qos\logback\logback-classic\1.2.6\logback-classic-1.2.6.jar;C:\Users\yi\.m2\repository\ch\qos\logback\logback-core\1.2.6\logback-core-1.2.6.jar;C:\Users\yi\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.14.1\log4j-to-slf4j-2.14.1.jar;C:\Users\yi\.m2\repository\org\apache\logging\log4j\log4j-api\2.14.1\log4j-api-2.14.1.jar;C:\Users\yi\.m2\repository\org\slf4j\jul-to-slf4j\1.7.32\jul-to-slf4j-1.7.32.jar;C:\Users\yi\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;C:\Users\yi\.m2\repository\org\yaml\snakeyaml\1.28\snakeyaml-1.28.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.5.6\spring-boot-starter-json-2.5.6.jar;C:\Users\yi\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.12.5\jackson-databind-2.12.5.jar;C:\Users\yi\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.12.5\jackson-annotations-2.12.5.jar;C:\Users\yi\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.12.5\jackson-core-2.12.5.jar;C:\Users\yi\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.12.5\jackson-datatype-jdk8-2.12.5.jar;C:\Users\yi\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.12.5\jackson-datatype-jsr310-2.12.5.jar;C:\Users\yi\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.12.5\jackson-module-parameter-names-2.12.5.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.5.6\spring-boot-starter-tomcat-2.5.6.jar;C:\Users\yi\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.54\tomcat-embed-core-9.0.54.jar;C:\Users\yi\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.54\tomcat-embed-el-9.0.54.jar;C:\Users\yi\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.54\tomcat-embed-websocket-9.0.54.jar;C:\Users\yi\.m2\repository\org\springframework\spring-web\5.3.12\spring-web-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\spring-beans\5.3.12\spring-beans-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\spring-webmvc\5.3.12\spring-webmvc-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\spring-aop\5.3.12\spring-aop-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\spring-context\5.3.12\spring-context-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\spring-expression\5.3.12\spring-expression-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-devtools\2.5.6\spring-boot-devtools-2.5.6.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot\2.5.6\spring-boot-2.5.6.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.5.6\spring-boot-autoconfigure-2.5.6.jar;C:\Users\yi\.m2\repository\org\springframework\boot\spring-boot-configuration-processor\2.5.6\spring-boot-configuration-processor-2.5.6.jar;C:\Users\yi\.m2\repository\org\projectlombok\lombok\1.18.22\lombok-1.18.22.jar;C:\Users\yi\.m2\repository\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;C:\Users\yi\.m2\repository\org\springframework\spring-core\5.3.12\spring-core-5.3.12.jar;C:\Users\yi\.m2\repository\org\springframework\spring-jcl\5.3.12\spring-jcl-5.3.12.jar;C:\Users\yi\.m2\repository\cn\hutool\hutool-all\5.7.15\hutool-all-5.7.15.jar;C:\Users\yi\.m2\repository\com\google\guava\guava\31.0.1-jre\guava-31.0.1-jre.jar;C:\Users\yi\.m2\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;C:\Users\yi\.m2\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;C:\Users\yi\.m2\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;C:\Users\yi\.m2\repository\org\checkerframework\checker-qual\3.12.0\checker-qual-3.12.0.jar;C:\Users\yi\.m2\repository\com\google\errorprone\error_prone_annotations\2.7.1\error_prone_annotations-2.7.1.jar;C:\Users\yi\.m2\repository\com\google\j2objc\j2objc-annotations\1.3\j2objc-annotations-1.3.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacv-platform\1.5.5\javacv-platform-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacv\1.5.5\javacv-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect2\0.2.0-1.5.5\libfreenect2-0.2.0-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\videoinput\0.200-1.5.5\videoinput-0.200-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5.jar;C:\Users\yi\.m2\repository\org\openjfx\javafx-graphics\11\javafx-graphics-11.jar;C:\Users\yi\.m2\repository\org\openjfx\javafx-graphics\11\javafx-graphics-11-win.jar;C:\Users\yi\.m2\repository\org\openjfx\javafx-base\11\javafx-base-11.jar;C:\Users\yi\.m2\repository\org\openjfx\javafx-base\11\javafx-base-11-win.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas-platform\0.3.13-1.5.5\openblas-platform-0.3.13-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp-platform\1.5.5\javacpp-platform-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-ios-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-ios-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-macosx-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\javacpp\1.5.5\javacpp-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-ios-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-ios-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\openblas\0.3.13-1.5.5\openblas-0.3.13-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv-platform\4.5.1-1.5.5\opencv-platform-4.5.1-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-ios-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-ios-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\opencv\4.5.1-1.5.5\opencv-4.5.1-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg-platform\4.3.2-1.5.5\ffmpeg-platform-4.3.2-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\ffmpeg\4.3.2-1.5.5\ffmpeg-4.3.2-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture-platform\2.13.3.31-1.5.5\flycapture-platform-2.13.3.31-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\flycapture\2.13.3.31-1.5.5\flycapture-2.13.3.31-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394-platform\2.2.6-1.5.5\libdc1394-platform-2.2.6-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\libdc1394\2.2.6-1.5.5\libdc1394-2.2.6-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect-platform\0.5.7-1.5.5\libfreenect-platform-0.5.7-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect\0.5.7-1.5.5\libfreenect-0.5.7-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect2-platform\0.2.0-1.5.5\libfreenect2-platform-0.2.0-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect2\0.2.0-1.5.5\libfreenect2-0.2.0-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect2\0.2.0-1.5.5\libfreenect2-0.2.0-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect2\0.2.0-1.5.5\libfreenect2-0.2.0-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\libfreenect2\0.2.0-1.5.5\libfreenect2-0.2.0-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense-platform\1.12.4-1.5.5\librealsense-platform-1.12.4-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense\1.12.4-1.5.5\librealsense-1.12.4-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2-platform\2.40.0-1.5.5\librealsense2-platform-2.40.0-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\librealsense2\2.40.0-1.5.5\librealsense2-2.40.0-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\videoinput-platform\0.200-1.5.5\videoinput-platform-0.200-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\videoinput\0.200-1.5.5\videoinput-0.200-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\videoinput\0.200-1.5.5\videoinput-0.200-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus-platform\2.3.1-1.5.5\artoolkitplus-platform-2.3.1-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\artoolkitplus\2.3.1-1.5.5\artoolkitplus-2.3.1-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark-platform\1.07-1.5.5\flandmark-platform-1.07-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\flandmark\1.07-1.5.5\flandmark-1.07-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica-platform\1.80.0-1.5.5\leptonica-platform-1.80.0-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\leptonica\1.80.0-1.5.5\leptonica-1.80.0-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract-platform\4.1.1-1.5.5\tesseract-platform-4.1.1-1.5.5.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-android-arm.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-android-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-android-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-android-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-linux-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-linux-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-linux-armhf.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-linux-arm64.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-linux-ppc64le.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-macosx-x86_64.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-windows-x86.jar;C:\Users\yi\.m2\repository\org\bytedeco\tesseract\4.1.1-1.5.5\tesseract-4.1.1-1.5.5-windows-x86_64.jar;C:\Users\yi\.m2\repository\xyz\downgoon\snowflake\1.0.0\snowflake-1.0.0.jar com.huyi.csdn.tools.SemaphoreDemo
17:23:20.516 [main] INFO com.huyi.csdn.tools.SemaphoreDemo - >>> 任务队列初始化
17:23:20.519 [main] INFO com.huyi.csdn.tools.SemaphoreDemo - >>> 任务引擎启动
17:23:20.559 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:21.572 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:1 任务获得执行许可
17:23:21.575 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:1 任务提交执行
17:23:21.577 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:22.568 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:2 任务获得执行许可
17:23:22.568 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:2 任务提交执行
17:23:22.568 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:22.584 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:23.561 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:3 任务获得执行许可
17:23:23.561 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:3 任务提交执行
17:23:23.561 [TASK-3] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:23.576 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:23.592 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 第3次进攻敌方基地
17:23:24.571 [TASK-3] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:24.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 执行任务数量已经达到限制,无法执行任务
17:23:24.587 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第3次进攻敌方基地
17:23:24.602 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 第4次进攻敌方基地
17:23:25.565 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 执行任务数量已经达到限制,无法执行任务
17:23:25.581 [TASK-3] INFO com.huyi.csdn.tools.SemaphoreDemo - 第3次进攻敌方基地
17:23:25.596 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第4次进攻敌方基地
17:23:25.611 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 第5次进攻敌方基地
17:23:26.570 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 执行任务数量已经达到限制,无法执行任务
17:23:26.584 [TASK-3] INFO com.huyi.csdn.tools.SemaphoreDemo - 第4次进攻敌方基地
17:23:26.600 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第5次进攻敌方基地
17:23:26.615 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:26.615 [TASK-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:1-结束任务
17:23:27.573 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:4 任务获得执行许可
17:23:27.573 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:4 任务提交执行
17:23:27.574 [TASK-4] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:27.574 [TASK-4] INFO com.huyi.csdn.tools.SemaphoreDemo - code:4-结束任务
17:23:27.589 [TASK-3] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:27.589 [TASK-3] INFO com.huyi.csdn.tools.SemaphoreDemo - code:3-结束任务
17:23:27.605 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第6次进攻敌方基地
17:23:28.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:5 任务获得执行许可
17:23:28.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:5 任务提交执行
17:23:28.571 [TASK-5] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:28.618 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 第7次进攻敌方基地
17:23:29.565 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:6 任务获得执行许可
17:23:29.565 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:6 任务提交执行
17:23:29.565 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:29.581 [TASK-5] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:29.628 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:29.628 [TASK-2] INFO com.huyi.csdn.tools.SemaphoreDemo - code:2-结束任务
17:23:30.571 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:30.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:7 任务获得执行许可
17:23:30.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:7 任务提交执行
17:23:30.571 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:30.586 [TASK-5] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:30.586 [TASK-5] INFO com.huyi.csdn.tools.SemaphoreDemo - code:5-结束任务
17:23:31.561 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:8 任务获得执行许可
17:23:31.561 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:8 任务提交执行
17:23:31.561 [TASK-8] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:31.577 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - 第3次进攻敌方基地
17:23:31.577 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:32.572 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 执行任务数量已经达到限制,无法执行任务
17:23:32.572 [TASK-8] INFO com.huyi.csdn.tools.SemaphoreDemo - 第2次进攻敌方基地
17:23:32.587 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第3次进攻敌方基地
17:23:32.587 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - 第4次进攻敌方基地
17:23:33.564 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 执行任务数量已经达到限制,无法执行任务
17:23:33.581 [TASK-8] INFO com.huyi.csdn.tools.SemaphoreDemo - 第3次进攻敌方基地
17:23:33.596 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第4次进攻敌方基地
17:23:33.596 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - 第5次进攻敌方基地
17:23:34.561 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 执行任务数量已经达到限制,无法执行任务
17:23:34.592 [TASK-8] INFO com.huyi.csdn.tools.SemaphoreDemo - 第4次进攻敌方基地
17:23:34.607 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第5次进攻敌方基地
17:23:34.607 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:34.607 [TASK-6] INFO com.huyi.csdn.tools.SemaphoreDemo - code:6-结束任务
17:23:35.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:9 任务获得执行许可
17:23:35.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:9 任务提交执行
17:23:35.571 [TASK-9] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:35.602 [TASK-8] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:35.602 [TASK-8] INFO com.huyi.csdn.tools.SemaphoreDemo - code:8-结束任务
17:23:35.617 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第6次进攻敌方基地
17:23:36.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:10 任务获得执行许可
17:23:36.571 [TASK-9] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:36.571 [TASK-9] INFO com.huyi.csdn.tools.SemaphoreDemo - code:9-结束任务
17:23:36.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - code:10 任务提交执行
17:23:36.571 [TASK-10] INFO com.huyi.csdn.tools.SemaphoreDemo - 第1次进攻敌方基地
17:23:36.617 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第7次进攻敌方基地
17:23:37.564 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:37.579 [TASK-10] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:37.579 [TASK-10] INFO com.huyi.csdn.tools.SemaphoreDemo - code:10-结束任务
17:23:37.626 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 第8次进攻敌方基地
17:23:38.568 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:38.630 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - 进攻结束
17:23:38.630 [TASK-7] INFO com.huyi.csdn.tools.SemaphoreDemo - code:7-结束任务
17:23:39.565 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:40.563 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:41.567 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:42.562 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:43.572 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:44.563 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:45.572 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:46.563 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:47.571 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:48.561 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:49.572 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行
17:23:50.570 [ENGINE-1] INFO com.huyi.csdn.tools.SemaphoreDemo - 队列为空,无任务需要执行

Process finished with exit code -1

可以看出,始终只有3个任务在执行任务。

补充

独占锁与共享锁

我发现很多人会把独占锁与公平锁搞混,其实他们不在一个方向上。

独占锁

独占锁是指在同一个时间只能有一个线程占有他,所以具备排他性。像synchronized关键字就是典型的独占锁。

举个栗子:独占锁相当于独间的澡堂,一个人进了这件澡堂,其他人都不能进,只有等他出来。

共享锁

什么是共享锁?

就是指同一时间可以被多个线程占有,像java自带的ReadWriteLock、Semaphore,他们可以设置自己共享的数量。

举个栗子:共享锁相当于一个大型公共澡堂,一开始就设定了能进去洗澡人的数量,比如是10个人,那么你要进去的时候会检查一下有没有满10个,满了你就在门口排队去吧。

公平锁与非公平锁

如果你在排队买奶茶,有个人插队了但是没人制止,你生不生气?他买到了奶茶扬长而去,这公不公平。

公平锁

公平锁就是多个线程去申请锁的使用权的时候,线程会直接进入队列排队,排在前面的可以先获得锁,排在后面的只能等着前面的先用。

举个栗子:有个澡堂,里面已经满了,后面的人想冲进去。但是有个保安站在门口,他让后面想进来的人都排好队,出来一个,就从队伍的前面放一个人进去。

没错,这就很公平。

但是公平锁也会带来其他的缺点,就是需要一个保安去控制,带来的其他开销。如果大家蜂拥而至去抢位置,少了这个保安,会更有效率。没错公平锁的缺点就是会带来更大的开销以及吞吐量下降。

非公平锁

与公平锁对应的就是非公平了,简而言之就是和公平锁反正来,什么不公平来什么。关键字synchronized就是典型的非公平锁。

缺点就是不公平,在某些场景中,特别是每次获取锁后会迅速执行并且释放锁的情况下,非公平锁是可以使用的。假设你洗澡的时间巨长,还有人插我队,这谁能忍得了?

可重入锁

可重入锁的概念很多人容易理解错,他是指同一个线程在申请到锁的情况下,继续申请锁不会阻塞,而是有个计数器记录该线程以及线程申请的次数。

举个栗子:还是单间浴室,但是我有一个洗澡卡,一旦我进了洗澡间就要刷卡,而且出来的时候还需要刷卡退出。那么我一旦进了洗澡间,我可以刷好几次进入卡,这不会阻塞住,因为都是我自己刷的。但是我退出洗澡间的时候我得刷同样次数的退出卡,不然下一个进来的人刷不了进入卡。好理解吗?你也别管我刷几次,反正我刷几次进入,就刷几次退出。

像java的关键字synchronized和ReentrantLock类都是可重入锁。

以上就是Java Semaphore实现高并发场景下的流量控制的详细内容,更多关于Java Semaphore流量控制的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java并发编程之工具类Semaphore的使用

    一.Semaphore的理解 Semaphore属于java.util.concurrent包: Semaphore翻译成字面意思为信号量,Semaphore可以控制同时访问的线程个数,通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可. 二.Semaphore类中常用方法 public void acquire() 用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许可. public void acquire(int permits) 获取permi

  • Java并发编程之Semaphore的使用简介

    简介 Semaphore是用来限制访问特定资源的并发线程的数量,相对于内置锁synchronized和重入锁ReentrantLock的互斥性来说,Semaphore可以允许多个线程同时访问共享资源. Semaphored的使用 构造方法 Semaphore(int permits):创建Semaphore,并指定许可证的数量.(公平策略为非公平) Semaphore(int permits, boolean fair):创建Semaphore,并指定许可证的数量和公平策略. 核心方法 acqu

  • Java基于Semaphore构建阻塞对象池

    java中使用Semaphore构建阻塞对象池 Semaphore是java 5中引入的概念,叫做计数信号量.主要用来控制同时访问某个特定资源的访问数量或者执行某个操作的数量. Semaphore中定义了一组虚拟的permits,通过获取和释放这些permits,Semaphore可以控制资源的个数. Semaphore的这个特性可以用来构造资源池,比如数据库连接池等. Semaphore有两个构造函数: public Semaphore(int permits) { sync = new No

  • 详解Java 信号量Semaphore

    Semaphore也是一个同步器,和前面两篇说的CountDownLatch和CyclicBarrier不同,这是递增的,初始化的时候可以指定一个值,但是不需要知道需要同步的线程个数,只需要在同步的地方调用acquire方法时指定需要同步的线程个数: 一.简单使用 同步两个子线程,只有其中两个子线程执行完毕,主线程才会执行: package com.example.demo.study; import java.util.concurrent.ExecutorService; import ja

  • java并发编程专题(六)----浅析(JUC)Semaphore

    半路开始看的朋友可以回顾一下前几篇 java并发编程专题(一)----线程基础知识 java并发编程专题(二)----如何创建并运行java线程 java并发编程专题(三)----详解线程的同步 java并发编程专题(四)----浅谈(JUC)Lock锁 java并发编程专题(五)----详解(JUC)ReentrantLock Semaphore,从字面意义上我们知道他是信号量的意思.在java中,一个计数信号量维护了一个许可集.Semaphore 只对可用许可的号码进行计数,并采取相应的行动

  • Java Semaphore实现高并发场景下的流量控制

    目录 前言 Semaphore介绍 代码演示 补充 独占锁与共享锁 公平锁与非公平锁 可重入锁 前言 在java开发的工作中是否会出现这样的场景,你需要实现一些异步运行的任务,该任务可能存在消耗大量内存的情况,所以需要对任务进行并发控制.如何优雅的实现并发控制呢?下面我会给大家介绍一个类--Semaphore,能很优雅的实现并发控制,继续往下看吧. Semaphore介绍 首先我们看一下Semaphore类的构造函数是如何实现的. public Semaphore(int permits, bo

  • 浅谈C++高并发场景下读多写少的优化方案

    目录 概述 分析 双缓冲 工程实现上需要攻克的难点 核心代码实现 简单说说golang中双缓冲的实现 相关文献 概述 一谈到高并发的优化方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也能很大的影响整体性能,本文从单模块下读多写少的场景出发,探讨其解决方案,以其更好的实现高并发.不同的业务场景,读和写的频率各有侧重,有两种常见的业务场景: 读多写少:典型场景如广告检索端.白名单更新维护.loadbalance

  • Redis高并发场景下秒杀超卖解决方案(秒杀场景)

    目录 1 什么是秒杀 2 为什么要防止超卖 3 单体架构常规秒杀 3.1 常规减库存代码 3.2 模拟高并发 3.3 超卖现象 3.4 分析原因 4 简单实现悲观乐观锁解决单体架构超卖 4.1 悲观锁 4.2 乐观锁 4.3 redis锁setnx 4.4 使用Redision 5 分布式锁的解决方案 6 采用缓存队列防止超卖 1 什么是秒杀 秒杀最直观的定义:在高并发场景下而下单某一个商品,这个过程就叫秒杀 [秒杀场景] 火车票抢票 双十一限购商品 热度高的明星演唱会门票 … 2 为什么要防止

  • 详解nginx高并发场景下的优化

    在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题.今天这里简单梳理下nginx性能优化的配置(仅仅依据本人的实战经验而述,如有不妥,敬请指出~) 一.这里的优化主要是指对nginx的配置优化,一般来说nginx配置文件中对优化比较有作用的主要有以下几项: 1)nginx进程数,建议按照cpu数目来指定,一般跟cpu核数相同或为它的倍数. worker_processes 8; 2)为每个进程分配cpu,上例中将8个进程分配到8个cpu,当然可以写多个

  • java高并发情况下高效的随机数生成器

    前言 在代码中生成随机数,是一个非常常用的功能,并且JDK已经提供了一个现成的Random类来实现它,并且Random类是线程安全的. 下面是Random.next()生成一个随机整数的实现: protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend)

  • java web在高并发和分布式下实现订单号生成唯一的解决方案

    方案一: 如果没有并发,订单号只在一个线程内产生,那么由于程序是顺序执行的,不同订单的生成时间戳正常不同,因此用时间戳+随机数(或自增数)就可以区分各个订单.如果存在并发,且订单号是由一个进程中的多个线程产生的,那么只要把线程ID添加到序列号中就可以保证订单号唯一.如果存在并发,且订单号是由同一台主机中的多个进程产生的,那么只要把进程ID添加到序列号中就可以保证订单号唯一.如果存在并发,且订单号是由不同台主机产生的,那么MAC地址.IP地址或CPU序列号等能够区分主机的号码添加到序列号中就可以保

  • J2ee 高并发情况下监听器实例详解

    J2ee 高并发情况下监听器实例详解 引言:在高并发下限制最大并发次数,在web.xml中用过滤器设置参数(最大并发数),并设置其他相关参数.详细见代码. 第一步:配置web.xml配置,不懂的地方解释一下:参数50通过参数名maxConcurrent用在filter的实现类中获取,filter-class就是写的实现类, url-pattern就是限制并发时间的url,结束! <filter> <filter-name>ConcurrentCountFilter</filt

  • Java进阶之高并发核心Selector详解

    一.Selector设计 笔者下载得是openjdk8的源码, 画出类图 比较清晰得看到,openjdk中Selector的实现是SelectorImpl,然后SelectorImpl又将职责委托给了具体的平台,比如图中框出的 linux2.6以后才有的EpollSelectorImpl Windows平台是WindowsSelectorImpl MacOSX平台是KQueueSelectorImpl 从名字也可以猜到,openjdk肯定在底层还是用epoll,kqueue,iocp这些技术来实

  • Redis高并发情况下并发扣减库存项目实战

    目录 第一种方案:纯MySQL扣减实现 MySQL架构升级 第二种方案:缓存实现扣减 第三种方案:数据库+缓存 顺序写的性能更好 顺序写的架构 扣减流程 相信大家从网上学习项目大部分人第一个项目都是电商,生活中时时刻刻也会用到电商APP,例如淘宝,京东等.做技术的人都知道,电商的业务逻辑简单,但是大部分电商都会涉及到高并发高可用,对并发和对数据的处理要求是很高的.这里我今天就讲一下高并发情况下是如何扣减库存的? 我们对扣减库存所需要关注的技术点如下: 当前剩余的数量大于等于当前需要扣减的数量,不

  • java的多线程高并发详解

    1.JMM数据原子操作 read(读取)∶从主内存读取数据 load(载入):将主内存读取到的数据写入工作内存 use(使用):从工作内存读取数据来计算 assign(赋值):将计算好的值重新赋值到工作内存中 store(存储):将工作内存数据写入主内存 write(写入):将store过去的变量值赋值给主内存中的变量 lock(锁定):将主内存变量加锁,标识为线程独占状态 unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量 2.来看volatile关键字 (1)启动两个线程

随机推荐