You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Executor框架中模拟线程饥饿与生产环境线程挂死场景?

Hey there! Let's tackle your two technical questions with clear, actionable examples that you can run directly to reproduce the scenarios you're curious about.


1. Simulating Thread Starvation in the Executor Framework

Thread starvation happens when certain threads never get access to the resources they need to run (like CPU time or locks) and are stuck waiting indefinitely. Here's how to replicate it using Java's Executor framework:

Scenario Setup

We'll use a FixedThreadPool with a small fixed size, then submit a few "greedy" tasks that hog the pool's threads forever. Any subsequent normal tasks will sit in the waiting queue, never getting a chance to execute—this is classic thread starvation.

Code Example

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorStarvationDemo {
    public static void main(String[] args) {
        // Create a thread pool with 2 core threads
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // Submit 2 greedy tasks that will hold threads indefinitely
        for (int i = 0; i < 2; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("Greedy Task " + taskId + " started—holding thread forever...");
                try {
                    // Simulate non-stop work that never releases the thread
                    while (true) {
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
        }

        // Submit 5 normal tasks that will starve
        for (int i = 0; i < 5; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("Normal Task " + taskId + " finally executed!");
            });
        }
    }
}

What You'll See

When you run this, the two greedy tasks will keep printing their status, but the normal tasks will never run. The pool's 2 threads are completely occupied, so the normal tasks are stuck in the queue with no hope of execution—this is starvation.

Lock-Based Starvation Alternative

If you want to simulate starvation caused by a shared lock, use this variation:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LockStarvationDemo {
    private static final Object sharedLock = new Object();

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);

        // Submit a task that holds the lock forever
        executor.submit(() -> {
            synchronized (sharedLock) {
                System.out.println("Task A acquired lock—holding it indefinitely...");
                try {
                    while (true) {
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        // Submit tasks that wait for the locked resource
        for (int i = 0; i < 2; i++) {
            int taskId = i;
            executor.submit(() -> {
                System.out.println("Task B" + taskId + " waiting for lock...");
                synchronized (sharedLock) {
                    System.out.println("Task B" + taskId + " acquired lock—executing...");
                }
            });
        }
    }
}

Here, Tasks B0 and B1 will forever print "waiting for lock" because Task A never releases the shared lock.


2. Replicating Web Service Thread Hang Caused by a Synchronized Method

Your production issue happened because every request thread was blocked on a synchronized method—either the thread holding the lock never released it, or the lock was held so long that all request threads piled up and the service became unresponsive. Let's replicate that:

Scenario Setup

We'll mimic a web service where each request runs in its own thread, and all threads call a synchronized core method. We'll make this method hang indefinitely (e.g., wait for a never-resolved condition), so the first thread to enter holds the lock forever, blocking all subsequent request threads.

Code Example

import java.util.concurrent.CountDownLatch;

public class WebServiceHangDemo {
    // Simulated core synchronized method that all requests depend on
    private synchronized void coreServiceMethod() {
        System.out.println(Thread.currentThread().getName() + " entered core method—processing...");
        try {
            // Simulate an infinite wait (e.g., waiting for a failed external service that never responds)
            new CountDownLatch(1).await(); // This latch will never be counted down
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println(Thread.currentThread().getName() + " finished core method");
    }

    // Simulate request handling logic
    private void handleRequest(String requestId) {
        System.out.println("Processing request: " + requestId + " | Thread: " + Thread.currentThread().getName());
        coreServiceMethod(); // All requests hit this synchronized method
        System.out.println("Request " + requestId + " completed");
    }

    public static void main(String[] args) {
        WebServiceHangDemo service = new WebServiceHangDemo();

        // Simulate 10 concurrent requests, each in a separate thread
        for (int i = 1; i <= 10; i++) {
            int requestNum = i;
            new Thread(() -> {
                service.handleRequest("REQ-" + requestNum);
            }, "Request-Thread-" + i).start();
        }
    }
}

What You'll See

The first thread (e.g., Request-Thread-1) will enter the core method and get stuck waiting on the CountDownLatch. All other threads will print "Processing request..." and then freeze—they're blocked at the entrance to coreServiceMethod() waiting for the lock, which is never released. This exactly replicates the "thread hang" scenario where your service couldn't handle new requests.

More Realistic Production Variation

If you want to mimic a scenario where the locked method calls a timed-out external service, replace the CountDownLatch with a long sleep:

private synchronized void coreServiceMethod() {
    System.out.println(Thread.currentThread().getName() + " entered core method—calling external service...");
    try {
        // Simulate an infinitely long external service call
        Thread.sleep(Integer.MAX_VALUE);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
}

The result is the same: the first thread holds the lock forever, and all other request threads block indefinitely.


内容的提问来源于stack exchange,提问作者Vijay Kumar Chauhan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:27:20