2
public class Test { private static final Object lock = new Object(); public static void main(String[] args) { try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { for (int i = 0; i < 100; i++) { int taskId = i; executor.submit(() -> performTask(taskId)); } } System.out.println("All tasks completed."); } private static void performTask(int id) { System.out.printf("Task %d started. Thread: %s%n", id, Thread.currentThread()); synchronized (lock) { System.out.printf("Task %d acquired lock. Thread: %s%n", id, Thread.currentThread()); try { Thread.sleep(Duration.ofSeconds(2)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } System.out.printf("Task %d finished. Thread: %s%n", id, Thread.currentThread()); } } 

In theory this should behave like serial execution, but in practice it kind of freezes up like a deadlock.

I’ve been stuck on this for days and really need some help.

5
  • I can't say I understand what's going on here, but I can say that if you comment out the last call to System.out.printf, i.e. the one that reports that the task has finished, then the deadlock goes away. Commented Nov 19 at 11:47
  • @LukeWoodward I’ve noticed this as well: comment out either the start or finish printf prevents the "deadlock". This might be related to the synchronized inside printf, but why does this happen if the code logic is correct? Commented Nov 20 at 1:30
  • I have no idea why, I'm afraid. My comment was only an observation rather than an answer. It's possible that this change doesn't entirely get rid of the deadlock, only makes it less likely to occur. If you want a proper fix to the problem, see the answer posted by igor.zh. Commented Nov 20 at 10:53
  • Read linkedin.com/posts/… Commented Nov 24 at 11:55
  • And much more details are available at netflixtechblog.com/… Commented Nov 24 at 12:12

1 Answer 1

1

Your code is perfectly correct from the standpoint of concurrency logic, but it causes virtual thread pinning, which is not a classic deadlock:

A virtual thread is pinned in the following situations: The virtual thread runs code inside a synchronized block or method

That's exactly what you have in the line

 synchronized (lock) 

To avoid the pinning you could:

  • migrate to Java 24 or newer;
  • replace synchronized with ReentrantLock-based implementation of Lock interface:
 private static final Lock lock = new ReentrantLock(); public static void main(String[] args) { try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { for (int i = 0; i < 100; i++) { int taskId = i; executor.submit(() -> performTask(taskId)); } } System.out.println("All tasks completed."); } private static void performTask(int id) { System.out.printf("Task %d started. Thread: %s%n", id, Thread.currentThread()); lock.lock(); try { System.out.printf("Task %d acquired lock. Thread: %s%n", id, Thread.currentThread()); try { Thread.sleep(Duration.ofSeconds(2)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } finally { lock.unlock(); } System.out.printf("Task %d finished. Thread: %s%n", id, Thread.currentThread()); } 

Even if the solution, offered by @LukeWoodward, might work (for some reason), I'd stay away from it because it does not eliminate the condition, described in virtual threads guidelines.

Sign up to request clarification or add additional context in comments.

3 Comments

I know that using synchronized will cause pinning, but it still shouldn’t result in a "deadlock"—the code logic is completely correct.
I’ve noticed that comment out either the start or finish printf prevents the "deadlock". This might be related to the synchronized inside printf, but why does this happen if the code logic is correct?
Like I said it is not a real deadlock: none of your threads is waiting for another while that another is waiting for first one. It is not your bug, it is JVM bug - in a sense. Why this JVM bug manifests itself when printf is on the table is a question to JVM people, not Java developers. Soon I'll try to update my answer with an attempt to clarify the deadlocks, both Java and JVM developers, issue.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.