Get the latest tech news
Discovering a JDK Race Condition, and Debugging It in 30 Minutes with Fray
Discovering a JDK Race Condition, and Debugging it in 30 Minutes with Fray I’ve been adding more integration tests for Fray recently. To ensure Fray can handle different scenarios, I wrote many creative test cases. Many of them passed as expected, while some failures led to epic fixes in Fray. Then something unexpected happened: Fray threw a deadlock exception while testing the following seemingly innocent code: 1private void test() { 2 ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1); 3 // Shutdown thread. 4 new Thread(() -> { 5 executor.shutdown(); 6 }).start(); 7 try { 8 ScheduledFuture<?> future = executor.schedule(() -> { 9 Thread.yield(); 10 }, 10, TimeUnit.MILLISECONDS); 11 try { 12 future.get(); 13 Thread.yield(); 14 } catch (Throwable e) {} 15 } catch (RejectedExecutionException e) {} 16} This code creates a ScheduledThreadPoolExecutor, schedules a task, and shuts down the executor in another thread. Initially, I suspected a bug in Fray, but after investigation, I discovered that the deadlock was actually caused by a bug in the JDK itself.
Then something unexpected happened: Fray threw a deadlock exception while testing the following seemingly innocent code: While the bug is conceptually simple, reaching this state is not straightforward because ScheduledThreadPoolExecutor and ThreadPoolExecutor are designed to prevent such situations. For example, in the tryTerminate method (Line 23-29), ThreadPoolExecutor checks whether the work queue is empty and workers are interrupted before setting the state to TIDYING.
Or read this on Hacker News