I have many threads to start. Some of them have the same name. I want to block a thread if its name is the same with another thread which is running. But if there is not a running thread with the same name, it can run immediately.
For example, I have 3 threads: A1, A2, B, and a thread pool. A1's name is "A", A2's name is "A", B's name is "B". When I execute the threads, if the start sequence is A1, A2, B, I want A2 is running after A1 has finished. But B is not affected for it's name is not "A". So B will run immediately.
Is there a simple implement? or I have to use Map?
CodePudding user response:
One thread can't safely block another (non-cooperating) thread.
There is ... Thread.suspend()
... but the javadoc says this:
Deprecated, for removal: This API element is subject to removal in a future version.
This method has been deprecated, as it is inherently deadlock-prone. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed. If the thread that would resume the target thread attempts to lock this monitor prior to calling resume, deadlock results. Such deadlocks typically manifest themselves as "frozen" processes. For more information, see Why are
Thread.stop
,Thread.suspend
andThread.resume
Deprecated?.
Even with cooperating threads (where one thread voluntarily blocks itself until something happens) I am not aware of an existing concurrency class / API that provides what you are asking for; i.e. controlling task sequences based on thread names.
Maybe you can (and should) do what you want to achieve without relying on thread names. For example:
You could have a multiple executors each with its own queue, and a single worker thread. One for the "A" tasks, one for the "B" tasks, and so on.
You could implement this with
CompletionService
andCompletionStage
. Make "A2" aCompletionStage
that consumes "A1", and so on.
CodePudding user response:
I can't promise to give you the best solution because you have not described the underlying problem that you are trying to solve. (I.e., you have not named the "Y" in "XY Problem.") But, maybe I can offer some help.
It sounds as if your program maybe has different users ("A", "B", etc.) and it sounds as if the program creates new tasks ("A1", "A2", etc.) in response to user input. You want the tasks associated with any particular user to be executed sequentially, but you want to allow tasks belonging to different users to be executed concurrently.
Right now, you create a new thread for every new task. That's almost never a good idea. A better idea is to have a collection of worker threads that loop forever, picking tasks from a blocking queue and executing them:
import java.util.concurrent.BlockingQueue;
class Worker implements Runnable {
private final BlockingQueue<Runnable> taskQueue;
public Worker(BlockingQueue<Runnable> taskQueue) {
this.taskQueue = taskQueue;
}
@override
public void run() {
while (true) {
Runnable task = taskQueue.take();
task.run();
}
}
}
That's the heart of a simplistic thread pool. The Java standard library has a much more sophisticated thread pool implementation, ThreadPoolExecutor
, but it doesn't quite do what you want because it won't guarantee to run certain tasks sequentially.
A normal thread pool has just one task queue from which all of the worker threads take()
tasks. But if you had a thread pool in which each worker had its own queue, and if your thread pool had a Map<Category,BlockingQueue<task>>
then it could assign all of the tasks belonging to the same category (e.g., to the same user) to the same worker thread, and that thread would perform the tasks one-by-one. Meanwhile, tasks belonging to other users could be assigned to different workers, and they could be executed concurrently with the first user's tasks.
I don't know of any ready-made implementation of this idea. It's something you'd have to code for yourself. Also, I don't have space here to talk about details such as, how to choose the number of workers, how to map users to workers, how to provide a shutdown mechanism (if needed) etc.
You could get arbitrarily sophisticated. Especially with the user->worker mapping: If Users A and B both map to the same worker, and if that worker has a backlog of requests from A when a new request from B comes in while some other worker is idle, then a sophisticated implementation might change the mapping for user B.