java 防止线程阻塞排队线程

ryevplcw  于 2023-01-11  发布在  Java
关注(0)|答案(1)|浏览(154)

我有一个任务将使用不同的值运行多次。我希望阻止它执行两个相同的任务(基于字符串值)。下面是字符串的一个示例。这些值将更改,但为了简单起见,我在示例中包含了以下这些值。我通过ExecutorService提交这些任务。任务运行,但是第二个hi阻止了其他任务的运行。所以4/5的任务并发运行。一旦第一个hi的锁被释放,第五个任务继续运行,其他任务继续运行。是否有办法防止这种类型的任务阻塞,以便其他3个任务可以在它之前运行,从而在实际上有5个任务之前不会排队同时运行。
任务的提交:

executor.submit(new Task("hi"));
executor.submit(new Task("h"));
executor.submit(new Task("u"));
executor.submit(new Task("y"));
executor.submit(new Task("hi"));
executor.submit(new Task("p"));
executor.submit(new Task("o"));
executor.submit(new Task("bb"));

这个任务很简单,它只打印出字符串:

Lock l = getLock(x);
try {
l.lock();

System.out.println(x);

try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(Task.class.getName()).log(Level.SEVERE, null, ex);
}

} finally {
l.unlock();

}

我已经更新了帖子,让事情更清楚地理解...

dhxwm5r4

dhxwm5r41#

为了避免阻塞一个线程,你必须确保一个操作不会在另一个之前运行,例如,你可以使用CompletableFuture链接一个操作,在前一个操作完成后安排:

public static void main(String[] args) {
    ExecutorService es = Executors.newFixedThreadPool(2);
    for(int i = 0; i < 5; i++) submit("one", task("one"), es);
    for(int i = 0; i < 5; i++) submit("two", task("two"), es);
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(26));
    es.shutdown();
}

static Runnable task(String x) {
    return () -> {
        System.out.println(x);
        LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
    };
}

static final ConcurrentHashMap<String, CompletableFuture<Void>> MAP
    = new ConcurrentHashMap<>();

static final void submit(String key, Runnable task, Executor e) {
    CompletableFuture<Void> job = MAP.compute(key,
        (k, previous) -> previous != null?
            previous.thenRunAsync(task, e): CompletableFuture.runAsync(task, e));
    job.whenComplete((v,t) -> MAP.remove(key, job));
}

ConcurrentHashMap允许我们将这些情况作为原子更新来处理

  • 如果某个键不存在以前的将来,则只需计划操作,创建将来
  • 如果存在先前的将来,则链接该操作,以在先前的将来完成时进行调度;依附行为成为新的未来
  • 如果作业已完成,当且仅当它仍是当前作业时,双参数remove(key, job)才会将其删除

main方法中的示例演示了两个独立的操作如何在包含两个线程的线程池中运行,而不会在线程处阻塞。

相关问题