Java同步:如何使等待的线程不执行同步任务

huangapple go评论65阅读模式
英文:

Java synchronization: how to have waiting threads not execute the synchronized task

问题

假设我有一段Java代码,我希望它以同步方式执行,但是当拥有锁的线程释放该锁时,我不希望等待的线程再执行同步代码。我只希望它们等到同步代码执行完毕。

所以,当线程1进入同步代码(方法、代码块)时,它必须获得该代码的锁。随后的线程必须等待第一个线程完成代码的运行。到目前为止,这是常规的代码同步。

但在我的情况下,当第一个线程完成并释放锁时,我希望等待的线程跳过该同步的代码部分(这段代码更新了所有线程都使用的资源)。

如何在Java中使用同步功能来创建这个呢?目前我没有使用同步功能,而是使用一个包含锁的并发集合(context),就像下面的代码一样。但是,锁定的过程仍然需要以某种方式同步,因为两个线程能够获得对context的锁。

以下是您提供的代码的翻译部分:

/*
 * 一组可同时访问的上下文。
 */
private static final Set<String> LOCKED_CONTEXTS;

static {
    LOCKED_CONTEXTS = ConcurrentHashMap.newKeySet(); // 同时,我用Collections.synchronizedSet(new HashSet<>())替换了这行代码
}

...

if (!LOCKED_CONTEXTS.contains(context)) {

    LOCKED_CONTEXTS.add(context);
    log.debug("Locked context: {}", context);

    try {
        doTask();

    } finally {

        LOCKED_CONTEXTS.remove(context);
        log.debug("Released context: {}", context);
    }
} else {

    log.debug("等待上下文被释放: {}", context);

    while (LOCKED_CONTEXTS.contains(context)) {
    }

    log.debug("等待结束,上下文已释放: {}", context);
}

注意:翻译中的log.debug部分未包括在内,因为这些是日志消息,应该保持原样。

英文:

Suppose I have a piece of code in Java that I want to be executed synchronously, however when the thread that owns the lock releases that lock, I do not want waiting threads to execute the synchronized code any more. I just want them to wait until the synchronized code has finished running.

So, when thread 1 enters the synchronized code (method, code block) it must get a lock on that code. Any subsequent threads must then wait for the first thread to finish running the code. So far, regular code synchronization.

However in my case, when the first thread is finished, and releases the lock, I want the waiting threads to skip that synchronized piece of code (the code updates a resource that is used by all threads).

How would I go about creating this in Java using the synchronization features? Currently I am not using the sync features, instead I am using a concurrent collection holding the lock (context), like herebelow. However, the process of locking still needs to be synchronized somehow, because two threads are able to get a lock on the context.

Cheers!

Kjeld

	/*
	 * A concurrently accessible set of contexts.
	 */
	private static final Set&lt;String&gt; LOCKED_CONTEXTS;

	static {
		LOCKED_CONTEXTS = ConcurrentHashMap.newKeySet(); // meanwhile, I replaced this with Collections.synchronizedSet(new HashSet&lt;&gt;()) 
	}

...

        if (!LOCKED_CONTEXTS.contains(context)) {

			LOCKED_CONTEXTS.add(context);
			log.debug(&quot;Locked context: {}&quot;, context);

			try {
				doTask();

			} finally {

				LOCKED_CONTEXTS.remove(context);
				log.debug(&quot;Released context: {}&quot;, context);
			}
		} else {

			log.debug(&quot;Waiting for context to be released: {}&quot;, context);

			while (LOCKED_CONTEXTS.contains(context)) {
			}

			log.debug(&quot;The waiting is over, context is released: {}&quot;, context);
		}

答案1

得分: 2

我认为你想要将锁与信号量结合起来。

  • 在锁上进行 tryLock
  • 如果成功获得锁,进行工作。在工作结束时,将信号量标记为已完成
  • 如果未能获得锁,等待信号量完成
英文:

I think you want to combine a lock with a semaphore.

  • tryLock on the lock
  • if you got it, do work. At the end of the work, mark the semaphore as complete
  • if you did not get it, wait for the semaphore to complete

答案2

得分: 1

也许我没有完全理解您的用例,但从我所理解的情况来看,您希望一段代码在执行过程中仅运行一次,适用于所有触发器,但如果在前一个执行窗口之外发生任何触发器,则可以再次运行。

是否理解正确?

class Work {
  private volatile boolean done;

  void queueWorkOnce() {
    done = false;
    actualWork();
  }

  private synchronized void actualWork() {
    if (!done) {
      //TODO: do work
      done = true;
    }
  }
}
英文:

Maybe I don't fully understand your use-case, but from what I get you want a piece of code to only run once for all triggers during its execution, but again if any trigger happens outside of the previous execution window.

Does this cover it?

class Work {
  private volatile boolean done;

  void queueWorkOnce() {
    done = false;
    actualWork();
  }

  private synchronized void actualWork() {
    if (!done) {
      //TODO: do work
      done = true;
    }
  }
}

huangapple
  • 本文由 发表于 2020年9月15日 19:46:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/63901172.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定