{"record":{"id":"bf3265449bfee6ab","repo":"apache/dubbo","slug":"hashedwheeltimer-stop-cannot-be-called-from-time","errorCode":null,"errorMessage":"HashedWheelTimer.stop() cannot be called from TimerTask","messagePattern":"HashedWheelTimer\\.stop\\(\\) cannot be called from TimerTask","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java","lineNumber":343,"sourceCode":"                throw new IllegalStateException(\"cannot be started once stopped\");\n            default:\n                throw new Error(\"Invalid WorkerState\");\n        }\n\n        // Wait until the startTime is initialized by the worker.\n        while (startTime == 0) {\n            try {\n                startTimeInitialized.await();\n            } catch (InterruptedException ignore) {\n                // Ignore - it will be ready very soon.\n            }\n        }\n    }\n\n    @Override\n    public Set<Timeout> stop() {\n        if (Thread.currentThread() == workerThread) {\n            throw new IllegalStateException(\n                HashedWheelTimer.class.getSimpleName() +\n                    \".stop() cannot be called from \" +\n                    TimerTask.class.getSimpleName());\n        }\n\n        if (!WORKER_STATE_UPDATER.compareAndSet(this, WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) {\n            // workerState can be 0 or 2 at this moment - let it always be 2.\n            if (WORKER_STATE_UPDATER.getAndSet(this, WORKER_STATE_SHUTDOWN) != WORKER_STATE_SHUTDOWN) {\n                INSTANCE_COUNTER.decrementAndGet();\n            }\n\n            return Collections.emptySet();\n        }\n\n        try {\n            boolean interrupted = false;\n            while (workerThread.isAlive()) {\n                workerThread.interrupt();","sourceCodeStart":325,"sourceCodeEnd":361,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java#L325-L361","documentation":"IllegalStateException thrown by HashedWheelTimer.stop() when the calling thread is the timer's own worker thread. Stopping the timer from within a TimerTask (which executes on the worker thread) would deadlock — stop() joins the worker thread, and joining yourself is impossible. This is a self-deadlock prevention guard. The error message names both HashedWheelTimer and TimerTask to make the cause obvious.","triggerScenarios":"A TimerTask's run(Timeout) method (or code it invokes) calls timer.stop() on the same HashedWheelTimer that is executing it. Since tasks run on the worker thread, and stop() blocks waiting for the worker thread to terminate, this would deadlock.","commonSituations":"A timeout callback that tries to shut down the timer as part of cleanup; a 'final' timer task that intends to stop all scheduling; business logic inside a TimerTask that triggers application teardown including the timer.","solutions":["Never call timer.stop() from within a TimerTask — schedule the shutdown to happen on a different thread.","If you need to stop the timer after a task completes, set a flag in the task and call stop() from a separate (non-worker) thread.","Use a separate executor or a post-task callback mechanism to trigger timer shutdown from outside the worker thread."],"exampleFix":"// before — stop called from inside a task (runs on worker thread)\ntimer.newTimeout(new TimerTask() {\n    public void run(Timeout t) {\n        timer.stop(); // throws: would deadlock\n    }\n}, 5, TimeUnit.SECONDS);\n\n// after — defer stop to another thread\ntimer.newTimeout(new TimerTask() {\n    public void run(Timeout t) {\n        separateExecutor.execute(() -> timer.stop());\n    }\n}, 5, TimeUnit.SECONDS);","handlingStrategy":"validation","validationCode":"// Before calling stop(), verify the current thread is NOT the worker thread\npublic static void safeStop(HashedWheelTimer timer) {\n    // There is no public getter for workerThread; track it externally or\n    // simply never call stop() from within TimerTask.run()\n    if (Thread.currentThread().getName().contains(\"timeoutWorker\")) {\n        throw new IllegalStateException(\"Cannot stop timer from worker thread\");\n    }\n    timer.stop();\n}","typeGuard":null,"tryCatchPattern":"try {\n    timer.stop();\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"cannot be called from\")) {\n        // defer to another thread\n        separateExecutor.execute(timer::stop);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Never call timer.stop() from inside a TimerTask.run() method.","If a task must trigger shutdown, post the stop() call to a separate executor.","Design timer tasks to be stateless and never control the timer's lifecycle."],"tags":["timer","deadlock","lifecycle","shutdown"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}