如何检查线程是否在ExecutorService线程池中运行

10

如何检查线程是否在线程ExecutorService池中运行?

背景:
我想在线程池中的线程之间进行同步,如果设置了标志。 因此,如果标志设置为true以进行同步,则必须检查其他线程是否正在运行,或者等待其完成,然后使用同步调用阻塞线程,以便其他线程将等待该阻塞线程完成。

如果未设置标志,则无需同步,并且可以并行执行线程。

谢谢!


1
你能告诉我们一些关于你正在做什么以及为什么要这样做的背景信息吗? - Jonathan S. Fisher
尝试过 thread.isAlive() 吗? - Ankit
你的意思是什么?你是指一个“任务”是否正在运行吗?在“ExecutorService”中,总会有活着的“线程”。请发布您的代码,以便我们可以帮助您,而不是猜测您可能需要什么。 - Boris the Spider
@exabrial 我添加了我的问题背景。 - bram
你能退一步并解释一下为什么你想要这个吗?试着不谈论你需要完成的具体事项来提问。现在你的问题太过于与特定的解决方案紧密相关了。 - Gray
如果您运行的守护程序可触发,并且不希望重复请求导致多次运行,那么仅使用执行器服务是无法解决问题的。您需要将其与额外的队列配合使用,以确保时间上接近的重复请求不会导致重复运行。 - mindiga
3个回答

5

你需要使用一个Semaphore

这允许你拥有一定数量的"许可证"来完成工作。如果你只想同时运行一个任务,那么就使用一个带有一个许可证的Semaphore,否则就使用一个许可证数大于线程池中Thread数量的Semaphore

static class Worker implements Runnable {

    final Semaphore semaphore;

    public Worker(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            semaphore.acquire();
            try {
                //do stuff
            } finally {
                semaphore.release();
            }
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
}

public static void main(String[] args) {

    final int numThreads = 10;
    final ExecutorService executorService = Executors.newFixedThreadPool(10);
    final Semaphore semaphore;
    boolean myflag = true;
    if (myflag) {
        semaphore = new Semaphore(1);
    } else {
        semaphore = new Semaphore(numThreads);
    }
    final Worker worker = new Worker(semaphore);
    executorService.submit(worker);
}

这个例子有点牵强,因为当你只需要一个任务一次运行时,你可以使用newSingleThreadExecutor() - 但我假设你知道这一点,由于某种原因不能使用它。
编辑
在查看是否可以整理代码时,我发现了这个。 这暗示了一种更简洁的解决方案:
static interface TaskBlocker {

    void acquire();

    void release();
}

static class Worker implements Runnable {

    final TaskBlocker taskBlocker;

    public Worker(TaskBlocker taskBlocker) {
        this.taskBlocker = taskBlocker;
    }

    @Override
    public void run() {
        taskBlocker.acquire();
        try {
            //do stuff
        } finally {
            taskBlocker.release();
        }
    }
}

public static void main(String[] args) {

    final int numThreads = 10;
    final ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
    final TaskBlocker taskBlocker;
    boolean myflag = true;
    if (myflag) {
        taskBlocker = new TaskBlocker() {
            final Lock lock = new ReentrantLock();

            @Override
            public void acquire() {
                lock.lock();
            }

            @Override
            public void release() {
                lock.unlock();
            }
        };
    } else {
        taskBlocker = new TaskBlocker() {
            @Override
            public void acquire() {
            }

            @Override
            public void release() {
            }
        };
    }
    final Worker worker = new Worker(taskBlocker);
    executorService.submit(worker);
}

@Bhargav 有什么影响? - Boris the Spider
你知道的,确保在任何给定时间只有一个任务正在运行。 - Bhargav
@Bhargav 鉴于它只有一个Thread,它怎么会做其他事情呢? - Boris the Spider

4
如何检查线程是否在线程池ExecutorService中运行?
如果您只想知道线程是否在特定的ExecutorService中运行,可以使用特定的ThreadFactory创建ExecutorService,并让它将一些特殊属性附加到线程上,例如特殊名称。
private static final String EXECUTOR_THREADNAME_PREFIX = "ExecutorThread";

ThreadFactory threadFactory = new ThreadFactory() {

    private final AtomicInteger id = new AtomicInteger(0);

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setName(EXECUTOR_THREADNAME_PREFIX + "_" + id.incrementAndGet());
        return thread;
    }
};

myExecutor = Executors.newCachedThreadPool(threadFactory);

然后,在线程中,您只需检查名称是否以您的前缀开头:

if (Thread.currentThread().getName().startsWith(EXECUTOR_THREADNAME_PREFIX)) {
    // In executor.
} else {
    // Not in executor.
}

4
简而言之,你不需要这样做。执行器并不是用来这样使用的。如果你想手动管理线程,请不要使用执行器。如果你使用执行器,请将思维从线程转移到可运行对象(Runnable)。使用同步或者任何在java.util.concurrent中的高级抽象方法,使你的可运行对象或类和方法线程安全。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接