【问题标题】:Concurrently working tasks并行工作任务
【发布时间】:2016-05-19 21:23:41
【问题描述】:

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

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

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

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();

  }
}

TASK.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);
            }

        }

    }

这就是它现在的样子。

【问题讨论】:

  • 拨打showTASK_LIST()会发生什么?
  • mcve 会更容易回答这个问题
  • 所以您还没有编写任何代码来将任务放入列表或实现任何请求的功能?我们可以回答您不理解的问题,但通常我们不会完成家庭作业。
  • @JimGarrison 我不同意。我将所有任务放在 ArrayList 中,并编写了程序的很大一部分。打印方法也几乎准备好了,我只是不知道在 main 中调用它应该是静态的。反正它已经解决了。

标签: java task java.util.concurrent


【解决方案1】:

您需要将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

【讨论】:

  • 非常感谢!这些东西我总是有问题。同样的方法是将 Task 对象添加到构造函数中的 ArrayList 中。我尝试了 milion 选项,几个小时后我发现我需要做的就是将 ArrayList 的类型更改为静态 :)。非常感谢!
  • 没问题!很高兴我能帮上忙!请记住,任何static 方法都可以在不需要object 的情况下调用。
  • 好的,我想我会真正记住这一点更长的时间:D。顺便说一句,您对如何一一停止任务有什么建议吗?对于团体停留,我有一些想法,但可能要等到明天,因为它在波兰几乎是凌晨 1 点:D。
  • 我现在你可以做exec.shutdown();,它会停止当前运行的一切。我不知道您是否可以在任务运行时接受输入。
【解决方案2】:

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

您正在从一个线程更改任务状态(写入)并尝试从作为主线程的不同线程(读取)读取它:

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. 使用返回 Future 对象的 Executor submit() 方法(Future 有很多有用的方法,例如:isDone()、cancel()、get() 等...)
  3. 在主线程和任务类之外管理您的任务列表

StatusChangeListener

public interface StatusChangeListener {

  void statusChanged(String oldStatus, String newStatus);
}

主要

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;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多