Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 自定义多线程:限制要并行执行的某些类型的任务数量,而不限制其他类型的任务_Java_Multithreading_Concurrency_Threadpool - Fatal编程技术网

Java 自定义多线程:限制要并行执行的某些类型的任务数量,而不限制其他类型的任务

Java 自定义多线程:限制要并行执行的某些类型的任务数量,而不限制其他类型的任务,java,multithreading,concurrency,threadpool,Java,Multithreading,Concurrency,Threadpool,我有三种类型的任务:A、B、C 我想在N个线程中并行运行这些任务。假设任务列表如下所示: A, B, C, B, C, A, B, C 当然,我可以使用ExecutorService实现多线程执行,但问题是我一次最多需要执行一个C类型的任务。其他C类型的任务必须顺序执行,但与a和/或B任务并行执行 例如,3线程执行器可能处于以下任何状态: A B C A A A A C B B B C B B B B C A C A B C ... (允许一次执行多个A或B类任务,但一次最多只能执

我有三种类型的任务:
A、B、C

我想在N个线程中并行运行这些任务。假设任务列表如下所示:

A, B, C, B, C, A, B, C
当然,我可以使用
ExecutorService
实现多线程执行,但问题是我一次最多需要执行一个
C
类型的任务。其他
C
类型的任务必须顺序执行,但与
a
和/或
B
任务并行执行

例如,3线程执行器可能处于以下任何状态:

A B C
A A A
A C B
B B C
B B B
B C
A C 
A B 
C  
... 
(允许一次执行多个A或B类任务,但一次最多只能执行一个C类任务)

有什么方法可以在Java中实现这一点吗

更新

这就是我想到的方法这是正确的吗 在这里,我通过
ExecutorService
执行所有任务,在执行过程中,我将检查是否有任何其他C任务正在运行。如果没有,我将执行其他任务,我将把它添加到一个队列中,该队列将在成功完成任何其他任务时退出队列,并且我将检查任何C任务是否正在运行

public class Test {

public void startExecution() {
    Queue<String> runQ = new LinkedList<>();
    ThreadPool exec = (ThreadPool) Executors.newFixedThreadPool(RunSettings.getRunSettings().getThreadCount());
    while (!runQ.isEmpty() && !SystemDefaults.stopExecution.get()) {
        String TaskName = runQ.remove();
        Task t = new Task(TaskName);
        exec.execute(t, TaskName);

    }
    exec.shutdown();
    if (exec.awaitTermination(RunSettings.getRunSettings().getExecutionTimeOut(), TimeUnit.MINUTES)) {
        System.out.println("[CONTROL: ALL TEST TASKS COMPLETED SUCCESSFULLY.]");
    } else {
        System.out.println("[CONTROL: ALL THE TEST TASKS DID NOT COMPLETE SUCCESSFULLY IN STIPULATED TIME. FORCEFULLY FINALIZING.]");
        exec.shutdownNow();

    }
}
}
公共类测试{
公共无效开始执行(){
队列runQ=newlinkedlist();
ThreadPool exec=(ThreadPool)Executors.newFixedThreadPool(RunSettings.getRunSettings().getThreadCount());
而(!runQ.isEmpty()&&!SystemDefaults.stopExecution.get()){
字符串TaskName=runQ.remove();
任务t=新任务(任务名称);
exec.execute(t,任务名);
}
exec.shutdown();
if(exec.waittermination(RunSettings.getRunSettings().getExecutionTimeOut(),TimeUnit.MINUTES)){
System.out.println(“[控制:所有测试任务成功完成]”;
}否则{
System.out.println(“[控制:所有测试任务未在规定时间内成功完成。强制完成]”;
exec.shutdownNow();
}
}
}
我创建的线程池

public class ThreadPool extends ThreadPoolExecutor {

public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}

final String CTask = "TaskC";
Map<Runnable, String> TaskPool = new HashMap<>();
Queue<Runnable> TaskCList = new LinkedList<>();

@Override
protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    if (TaskPool.containsKey(r)) {
        TaskPool.remove(r);
    }
    if (!TaskPool.containsValue(CTask) && !TaskCList.isEmpty()) {
        Runnable ieRun = TaskCList.remove();
        super.execute(ieRun);
        TaskPool.put(ieRun, CTask);
    }
}

public void execute(Runnable command, String TaskType) {
    if (TaskPool.containsValue(TaskType)
            && TaskType.equalsIgnoreCase(CTask)) {
        System.out.println("Another Instance of  " + CTask + " Running");
        TaskCList.add(command);
    } else {
        super.execute(command);
        TaskPool.put(command, TaskType);
    }
}

}
公共类ThreadPool扩展ThreadPoolExecutor{
公共线程池(int corePoolSize、int maximumPoolSize、long keepAliveTime、TimeUnit、BlockingQueue workQueue){
super(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue);
}
最终字符串CTask=“TaskC”;
Map TaskPool=new HashMap();
Queue TaskCList=new LinkedList();
@凌驾
执行后受保护的无效(可运行的r、可丢弃的t){
super.afterExecute(r,t);
if(任务池容器(r)){
任务池。删除(r);
}
如果(!TaskPool.containsValue(CTask)&&&!TaskCList.isEmpty()){
Runnable ieRun=TaskCList.remove();
超级执行(ieRun);
TaskPool.put(ieRun,CTask);
}
}
public void execute(可运行命令,字符串TaskType){
if(TaskPool.containsValue(TaskType)
&&TaskType.equalsIgnoreCase(CTask)){
System.out.println(“另一个“+CTask+”正在运行的实例”);
TaskCList.add(命令);
}否则{
super.execute(命令);
TaskPool.put(命令,任务类型);
}
}
}

最简单的方法是创建两个执行器:一个单线程执行器用于C类型的任务,另一个多线程执行器用于其他类型的任务:

class ExecutorWrapper {
    private ExecutorService forC = Executors.newSingleThreadExecutor();
    private ExecutorService forAnother = Executors.newFixedThreadPool(THREAD_NUMBER);

    public void acceptTask(Runnable r) {
        if (r instanceof TaskC) {
            forC.execute(r);
        } else {
            forAnother.execute(r);
        }
    }
}
现在,任何C类型的任务都将在执行器内部队列中等待,直到另一个此类任务完成

如果不希望创建另一个执行器,则需要实现某种并发控制,因为可能会发生争用情况,这种并发控制要复杂得多,而且很难调试。我可以提出解决方案草案,但没有代码:

  • 创建一个标志,指示另一个任务C是否已在执行,以及另一个任务C将在其中等待的队列
  • 当C类型的任务到达时,检查另一个任务C是否正在执行,如果是,则将其添加到所述队列中
  • 在任务C完成时,发送某种任务C已完成的通知,以便从所述队列中获取下一个任务C并将其发送到Executor。如果队列为空,请清除该标志以指示当前没有正在执行的任务。这种通知可以通过使用
    Callable
    包装任务C,并调用
    Future#get
    方法来实现,该方法将一直阻止任务完成

  • 看起来您所需要做的就是使任务C
    同步。下面的一些测试代码似乎证明了这一点——尽管没有失败并不总是意味着成功

    结果清楚地表明A和B是并行运行的,但从来没有C

    static enum Task implements Callable<Void> {
    
        A,
        B,
        C {
                    @Override
                    public synchronized Void call() throws Exception {
                        if (running.get(this).get() != 0) {
                            System.out.println("FAIL!");
                        }
                        return super.call();
                    }
    
                };
    
        // How many of each are running.
        static Map<Task, AtomicInteger> running = Stream.of(Task.values())
                .collect(
                        Collectors.toMap(
                                (t) -> t,
                                (t) -> new AtomicInteger(0),
                                (x, y) -> x,
                                () -> new EnumMap<Task, AtomicInteger>(Task.class)));
    
        // List all running tasks.
        private String runningList() {
            StringBuilder s = new StringBuilder();
            running.entrySet().stream().forEach((r) -> {
                if (r.getValue().get() != 0) {
                    s.append(r.getKey()).append("=").append(r.getValue()).append(",");
                }
            });
            return s.toString();
        }
    
        static final Random random = new Random();
    
        @Override
        public Void call() throws Exception {
            System.out.println("Running " + name() + " with " + runningList());
            // Mark me running.
            running.get(this).getAndIncrement();
            // Hang around for a bit.
            Thread.sleep(random.nextInt(1000));
            // Mark me not running.
            running.get(this).getAndDecrement();
            return null;
        }
    
    }
    
    // The pool.
    static ExecutorService pool = Executors.newFixedThreadPool(5);
    // The tasks.
    static Task[] tasks = new Task[]{Task.A, Task.B, Task.C, Task.B, Task.C, Task.A, Task.B, Task.C,};
    
    public void test() throws InterruptedException {
        // Run 10 times.
        for (int i = 0; i < 10; i++) {
            pool.invokeAll(Arrays.asList(tasks));
        }
        pool.shutdown();
        pool.awaitTermination(10, TimeUnit.SECONDS);
    }
    
    静态枚举任务实现可调用{
    A.
    B
    C{
    @凌驾
    public synchronized Void call()引发异常{
    if(running.get(this.get()!=0){
    System.out.println(“失败!”);
    }
    返回super.call();
    }
    };
    //每个都有多少人在跑步。
    静态映射运行=Stream.of(Task.values())
    .收集(
    汤姆(
    (t) ->t,
    (t) ->新的原子整数(0),
    (x,y)->x,
    ()->新的枚举映射(Task.class));
    //列出所有正在运行的任务。
    私有字符串runningList(){
    StringBuilder s=新的StringBuilder();
    正在运行.entrySet().stream().forEach((r)->{
    如果(r.getValue().get()!=0){
    s、 append(r.getKey()).append(“=”).append(r.getValue()).append(“,”);
    }
    });
    返回s.toString();
    }
    静态最终随机=新随机();
    @凌驾
    public Void call()引发异常{
    System.out.println(“正在运行“+name()+”和“+runningList()”);
    //让我跑吧。
    正在运行.get(this.getAndIncrement();
    //亨格尔
    
    public class Test {
    
    public void startExecution() {
    Queue<String> runQ = new LinkedList<>();
    ThreadPool threadPool = new ThreadPool(threadCount,timeOut);
    while (!runQ.isEmpty()) {
        String TaskName = runQ.remove();
        Task t = new Task(TaskName);
        threadPool.execute(t, TaskName);
    
    }
    if (threadPool.awaitTermination(timeOut, TimeUnit.MINUTES)) {
        System.out.println("[CONTROL: ALL TEST TASKS COMPLETED SUCCESSFULLY.]");
    } else {
        System.out.println("[CONTROL: ALL THE TEST TASKS DID NOT COMPLETE SUCCESSFULLY IN STIPULATED TIME. FORCEFULLY FINALIZING.]");
        threadPool.shutdownNow();
    
    }
    }
    }
    
     public class ThreadPool extends ThreadPoolExecutor {
    
    public ThreadPool(int threadCount, long keepAliveTime) {
        super(threadCount, threadCount, keepAliveTime, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
    }
    
    final String CTask = "TaskC";
    Map<Runnable, String> TaskPool = new HashMap<>();
    Queue<Runnable> TaskCList = new LinkedList<>();
    
    @Override
    protected synchronized void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        System.out.println(TaskPool.get(r) + "Finished");
        if (TaskPool.containsKey(r)) {
            TaskPool.remove(r);
        }
        if (TaskCList.isEmpty()) {
            super.shutdown();
        }
        if (!TaskPool.containsValue(CTask) && !TaskCList.isEmpty()) {
            if (super.getActiveCount() < super.getCorePoolSize()) {
                System.out.println("Trying to execute Other C Tasks");
                Runnable ieRun = TaskCList.remove();
                super.execute(ieRun);
                TaskPool.put(ieRun, CTask);
            }
        }
    }
    
    public synchronized void execute(Runnable command, String TaskType) {
        if (TaskPool.containsValue(TaskType)
                && TaskType.equalsIgnoreCase(CTask)) {
            System.out.println("Another Instance of TaskC Running");
            System.out.println("Added for future Execution");
            TaskCList.add(command);
        } else {
            System.out.println("Adding " + TaskType + " to execution");
            TaskPool.put(command, TaskType);
            super.execute(command);
        }
    }