有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java并发工作任务

我正在准备一个简单的程序,它允许用户创建几个并发的工作任务。没什么特别的。每个任务从值1开始,在达到最大值时再加上一个1(每个任务得到不同的最大值)。然后,任务通知,已达到指定值并停止。所有任务都必须包含在ArrayList中,即我制作的。我需要提供方法,允许(在任何时刻)

  1. 检查任务的状态
  2. 检查任务的结果
  3. 单独或一次完成任务
  4. 显示列表,其中包含所有任务(名称、值、状态)

我宁愿避免使用gui,因为我的教授不需要它。我已经做了部分,但我不知道如何打印列表(任务列表)的所有元素并停止单个任务

MAIN。java

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

public class Main {

  public static void main(String[] args) {

    ExecutorService exec = Executors.newCachedThreadPool();

    Task t1 = new Task("Task 1", 2);
    Task t2 = new Task("Task 2", 20);
    Task t3 = new Task("Task 3", 5);

    exec.execute(t1);
    exec.execute(t2);
    exec.execute(t3);

    //showTASK_LIST();

  }
}

任务。java

    import java.util.ArrayList;
    import java.util.List;

    class Task implements Runnable {
        String TASK_NAME;
        int TASK_RESULT;
        int TASK_GOAL;
        String TASK_STATUS;
        static List<Task> TASK_LIST = new ArrayList<Task>();

        public Task(String name, int goal) {
            this.TASK_NAME = name;
            this.TASK_GOAL = goal;
            this.TASK_STATUS = "INACTIVE";
            TASK_LIST.add(this);
        }

        public void run() {
            TASK_STATUS="ACTIVE";
            System.out.println(TASK_NAME + " starts.");
            while (TASK_RESULT != TASK_GOAL){
                //if (Thread.currentThread().isInterrupted()) return;
                TASK_RESULT++;
                System.out.println(TASK_NAME + " " + TASK_RESULT);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Thread.yield();

            }
            System.out.println("===========================================\n" + 
                                TASK_NAME + " has been completed. Final result = " + TASK_GOAL +
                                "\n===========================================" );
            setTASK_STATUS("COMPLETED");
            System.out.println(TASK_LIST.size());


        }

        //Method to check current result
        public int getTASK_RESULT() {
            return TASK_RESULT;
        }

        //Method to check current status
        public String getTASK_STATUS() {
            return TASK_STATUS;
        }

        //Method to change result
        public void setTASK_STATUS(String status) {
            TASK_STATUS = status;
        }

        //This part doesnt work
        public showTASK_LIST(){
            for(int i = 0; i <= TASK_LIST.size(); i++){
                System.out.println(TASK_LIST.get(i).TASK_NAME);
            }

        }

    }

这就是目前的情况


共 (2) 个答案

  1. # 1 楼答案

    您的代码存在线程安全问题,因为您试图从多个线程读取/写入共享资源(本例中为任务对象)上的值:

    您正在从一个线程更改任务状态(写入),并尝试从另一个线程读取任务状态(读取),这是主线程。在这种情况下:

    Task.showTASK_LIST()
    

    同样的问题也存在于:

          //Method to check current result
        public int getTASK_RESULT() {
            return TASK_RESULT;
        }
    
        //Method to check current status
        public String getTASK_STATUS() {
            return TASK_STATUS;
        }
    

    有关Java并发性和线程安全的信息,请访问: https://en.wikipedia.org/wiki/Thread_safety https://docs.oracle.com/javase/tutorial/essential/concurrency/

    在重用代码的同时,我将提供自己的实现,但在此之前,请在深入研究代码之前先做几点注释:

    1. 使用Callable接口而不是Runnable,因为您希望在处理结束时返回结果(Callable类似于Runnable,但您可以返回结果)
    2. 使用Executor submit()方法返回Future对象(Future有许多有用的方法,如:isDone()、cancel()、get()等)
    3. 管理主线程中以及任务类之外的任务列表

    StatusChangeListener

    public interface StatusChangeListener {
    
      void statusChanged(String oldStatus, String newStatus);
    }
    

    Main

    import java.util.ArrayList;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class Main {
    
      public static void main(String[] args) {
    
        ExecutorService executor = Executors.newCachedThreadPool();
    
        //manage your tasks list here
        ArrayList<Task> tasks = new ArrayList<>();
        Task t1 = new Task("Task 1", 2);
        Task t2 = new Task("Task 2", 20);
        Task t3 = new Task("Task 3", 5);
    
        tasks.add(t1);
        tasks.add(t2);
        tasks.add(t3);
    
        //add status change listener to be notified for t1 status changes
        t1.addStatusChangeListener(new MyListener());
    
        System.out.println("tasks = " + tasks);
    
        //use submit instead of execute
        Future<Integer> future1 = executor.submit(t1);
    
        System.out.println("task 1 is done = " + future1.isDone());
    
        Future<Integer> future2 = executor.submit(t2);
        Future<Integer> future3 = executor.submit(t3);
        //cancel task 3
        future3.cancel(true);
    
        try {
          System.out.println("future 1 result= " + future1.get());
          System.out.println("future 2 result= " + future2.get());
        } catch (InterruptedException e) {
          e.printStackTrace();
        } catch (ExecutionException e) {
          e.printStackTrace();
        }
      }
    
      //you can do the same with the progress. e.g. add progress listener
      private static class MyListener implements StatusChangeListener{
    
        @Override
        public void statusChanged(String oldStatus, String newStatus) {
          System.out.println(String.format("Thread : %s status changed from %s to %s", Thread.currentThread(), oldStatus, newStatus));
        }
      }
    
    }
    

    任务

    import java.util.concurrent.Callable;
    
    class Task implements Callable<Integer> {
    
      //can be replaced by enum
      private String TASK_STATUS;
      private String TASK_NAME;
      private int TASK_RESULT;
      private int TASK_GOAL;
      private StatusChangeListener statusChangeListener;
    
    
      public Task(String name, int goal) {
        this.TASK_NAME = name;
        this.TASK_GOAL = goal;
        this.TASK_STATUS = "INACTIVE";
      }
    
      //private Method to change result
      private void setTASK_STATUS(String newStatus) {
        String oldStatus = TASK_STATUS;
        TASK_STATUS = newStatus;
        //notify status changes
        if (statusChangeListener != null)
          statusChangeListener.statusChanged(oldStatus, newStatus);
      }
    
      @Override
      public Integer call() throws Exception {
        setTASK_STATUS("ACTIVE");
        System.out.println(TASK_NAME + " starts.");
        while (TASK_RESULT != TASK_GOAL) {
          //if (Thread.currentThread().isInterrupted()) return;
          TASK_RESULT++;
          System.out.println(TASK_NAME + " " + TASK_RESULT);
          try {
            Thread.sleep(500);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          Thread.yield();
    
        }
        System.out.println("===========================================\n" +
                TASK_NAME + " has been completed. Final result = " + TASK_GOAL +
                "\n===========================================");
        setTASK_STATUS("COMPLETED");
        return TASK_RESULT;
      }
    
      public void addStatusChangeListener(StatusChangeListener statusChangeListener) {
        this.statusChangeListener = statusChangeListener;
      }
    }
    
  2. # 2 楼答案

    您需要将showTASK_LIST()设置为静态。然后可以用Task.showTASK_LIST();调用它

    如下

       public static void showTASK_LIST(){
            for(int i = 0; i <= TASK_LIST.size(); i++){
                System.out.println(TASK_LIST.get(i).TASK_NAME);
            }
    
    Task.showTASK_LIST();//goes in your main method to show the tasks
    

    运行代码时得到的结果在上述代码中产生了indexOutOfBounds异常。这是一个简单的解决方案

    将for循环更改为此

    for(int i = 0; i < TASK_LIST.size(); i++)// changed <= to <
    

    只有3个任务,<;=转到导致问题的第四个任务

    我得到了这个输出

    Task 1 starts.
    Task 3 starts.
    Task 3 1
    Task 1
    Task 2
    Task 3
    Task 2 starts.
    Task 1 1
    Task 2 1
    Task 3 2
    Task 1 2
    Task 2 2
    Task 3 3
    ===========================================
    Task 1 has been completed. Final result = 2
    ===========================================
    Task 2 3
    3
    Task 3 4
    Task 2 4
    Task 2 5
    Task 3 5
    Task 2 6
    ===========================================
    Task 3 has been completed. Final result = 5
    ===========================================
    3
    Task 2 7
    Task 2 8
    Task 2 9
    Task 2 10
    Task 2 11
    Task 2 12
    Task 2 13
    Task 2 14
    Task 2 15
    Task 2 16
    Task 2 17
    Task 2 18
    Task 2 19
    Task 2 20
    ===========================================
    Task 2 has been completed. Final result = 20
    ===========================================
    3