如何确保每个线程在不同的进程对象上工作以避免线程安全问题?

时间:2016-12-18 23:19:29

标签: java multithreading design-patterns thread-safety

我有两个过程,如下所示。我的每个流程都有<form id="Form" name="ReportForm" action="/Test/Report.action" method="post"> <table> <tr> <td><label class="formlabel"><font size="2pt">Name Name</font></label></td> <td> <select dojoType="struts:ComboBox" id="RportName" forceValidOption="true" autoComplete="true" dropdownWidth="300" size="1" keyName="selected" visibleDownArrow="false" searchLimit="10" > <option value="1">SharePoint</option> <option value="2">JavaCode</option> <option value="3">Cloud Services</option> <option value="4">SQL Database</option> <option value="5">Oracle</option> <option value="6">System</option> </select> <script language="JavaScript" type="text/javascript">djConfig.searchIds.push("Name");</script> run方法

shutdown
  • 我希望每个进程都有不同的线程池配置,以便ProcessA在其自己的线程池中运行,而ProcessB在其自己的线程池中独立运行。
  • 我无法在自己的线程池的每个线程之间共享Process对象。

以下是我如何使用自己的线程池运行Process processA = new ProcessA("processA", getProcessAProperties()); Process processB = new ProcessB("processB", getProcessBProperties()); 的简单示例。有三个线程,每个线程都有自己的Process对象来处理。现在我想以更通用的方式扩展它,以便它可以适用于我的两个进程,如上所示。

ProcessA

所以我创建了一个Process处理程序,以通用方式解决上述问题,但这里存在一个线程安全问题:

public static void main(String[] args) {
  int numberOfThreads = 3;
  ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads);

  final List<Process> processes = new ArrayList<>();
  for (int i = 0; i < numberOfThreads; i++) {
    // each thread works on different Process object
    Process processA = new ProcessA("processA", getProcessAProperties());
    processes.add(processA);
    executor.submit(processA);
  }

  Runtime.getRuntime().addShutdownHook(new Thread() {
    @Override
    public void run() {
      for (Process process : processes) {
        process.shutdown();
      } 
      executor.shutdown();
      try {
        executor.awaitTermination(5000, TimeUnit.MILLISECONDS);
      } catch (InterruptedException e) {
        e.printStackTrace;
      }
    }
  });
}

这就是我的主要方法现在的样子:

public final class ProcessHandler {
  private final ExecutorService executorServiceProcess;
  private final Process process;
  private final Thread shutdownHook = new Thread() {
    @Override
    public void run() {
      process.shutdown();
      executorServiceProcess.shutdown();
    }
  };

  // in this constructor my code is reusing the same 
  // process instance for each thread in the pool 
  // which is a problem for my application, how to fix this?
  public ProcessHandler(Process process, int poolSize) {
    this.executorServiceProcess = Executors.newFixedThreadPool(poolSize);
    this.process = process;
    Runtime.getRuntime().addShutdownHook(shutdownHook);     
    for (int i = 0; i < poolSize; i++) {
      executorServiceProcess.submit(process);
    }
  }

  public void shutdown() {
    Runtime.getRuntime().removeShutdownHook(shutdownHook);
    shutdownHook.start();
    try {
      shutdownHook.join();
    } catch (InterruptedException ex) {
      Thread.currentThread().interrupt();
    }
  }
}

正如您在上面的public static void main(String[] args) { Process processA = new ProcessA("processA", getProcessAProperties()); Process processB = new ProcessB("processB", getProcessBProperties()); // processA will run with three threads in its own thread pool ProcessHandler processHandlerA = new ProcessHandler (processA, 3); // processB will run with two threads in its own thread pool ProcessHandler processHandlerB = new ProcessHandler (processB, 2); // now I can call shutdown on them processHandlerA.shutdown(); processHandlerB.shutdown(); } 构造函数中所看到的,我正在为池中的每个线程重用相同的流程实例,这不是我想要做的。我希望每个线程都能在Process对象的不同实例上工作,就像我在ProcessA的第一个主方法中所做的那样,每个线程都在处理不同的Process对象。

解决此设计问题的最佳方法是什么?我也正在重新设计我的ProcessHandler,以正确的方式解决这个问题。

1 个答案:

答案 0 :(得分:1)

也许尝试这样的事情:

// Replace Process process by a list of Process
List<Process> processes = new ArrayList<Process>();

private final Thread shutdownHook = new Thread() {
    @Override
    public void run() {
      for (Process process : processes)
        process.shutdown();
      executorServiceProcess.shutdown();
    }
};

public ProcessHandler(Process process, int poolSize) {
    this.executorServiceProcess = Executors.newFixedThreadPool(poolSize);
    Runtime.getRuntime().addShutdownHook(shutdownHook);     
    for (int i = 0; i < poolSize; i++) {
      // Get a deep copy of the process
      Process p = process.clone();
      processes.add(p);
      executorServiceProcess.submit(p);
    }
}

另一种方法,没有克隆方法,是抽象Process并基于这些添加两个构造函数, 不要忘记根据这些元素调整代码

public abstract class AProcess extends Process {

    private String name;
    private Properties properties;
    public AProcess(String name, Properties properties)
    {
        this.setName(name);
        this.setProperties(properties);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

您现在必须实施ProcessA和ProcessB:

public class ProcessA extends AProcess {

    public ProcessA(String name, Properties properties)
    {
        super(name, properties);
    }
}

现在创建您的ProcessHandler:

public final class ProcessHandler {
  private final ExecutorService executorServiceProcess;
  private final List<AProcess> processes = new ArrayList<AProcess>();
  private final Thread shutdownHook = new Thread() {
    @Override
    public void run() {
      for (AProcess process : processes)
          process.shutdown();
      executorServiceProcess.shutdown();
    }
  };

  public ProcessHandler(ProcessA process, int poolSize) {
    this.executorServiceProcess = Executors.newFixedThreadPool(poolSize);
    Runtime.getRuntime().addShutdownHook(shutdownHook);     
    for (int i = 0; i < poolSize; i++) {
      ProcessA p = new ProcessA(process.getName(), process.getProperties());
      processes.add(p);
      executorServiceProcess.submit(p);
    }
  }

  public ProcessHandler(ProcessB process, int poolSize) {
    this.executorServiceProcess = Executors.newFixedThreadPool(poolSize);
    Runtime.getRuntime().addShutdownHook(shutdownHook);     
    for (int i = 0; i < poolSize; i++) {
      ProcessB p = new ProcessB(process.getName(), process.getProperties());
      processes.add(p);
      executorServiceProcess.submit(p);
    }
  }

  public void shutdown() {
    Runtime.getRuntime().removeShutdownHook(shutdownHook);
    shutdownHook.start();
    try {
      shutdownHook.join();
    } catch (InterruptedException ex) {
      Thread.currentThread().interrupt();
    }
  }
}

并使用ProcessHandler processHandlerA = new ProcessHandler(processA, 3);