【问题标题】:Running two tasks at the same time in Java在 Java 中同时运行两个任务
【发布时间】:2016-04-26 15:55:30
【问题描述】:

我想同时执行这两段代码。这是我到目前为止的代码:

@Path("/cases")
public class CaseResource {

    @GET
    @Path("/getCaseNumber")
    @Produces(MediaType.TEXT_PLAIN)
    public String getNextCaseNumber(
            @ApiParam(value = "tenant id", required = true)
            @HeaderParam("tenant_id") String tenantId) throws Exception {

        //Piece #1
        String caseNum1 = new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);
        Case tempCase = new Case();
        tempCase.setCaseStatusCode(new CodeService().getCodeForKeyGroup("ACTIVE","CASE_STATUS"));
        caseService.saveCase(tempCase, tenantId);

        //Piece #2 
        String caseNum2= new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);




        String caseNumbers = "{case1: " + caseNum1 + ", case2:" + caseNum2 + "}";
        return caseNumbers;
    }
}

这里一切正常,但我想同时执行以下任务:

任务1:输出caseNum1,保存新case到数据库

任务2:输出caseNum2

这是我尝试做的:

@Path("/cases")
public class CaseResource {
    String  caseNum1;
    String caseNum2;


    @GET
    @Path("/getCaseNumber")
    @Produces(MediaType.TEXT_PLAIN)
    public String getNextCaseNumber(
            @ApiParam(value = "tenant id", required = true)
            @HeaderParam("tenant_id") final String tenantId) throws Exception {

        new Thread(new Runnable() {
            public void run() {
                caseNum1= new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);
                Case tempCase = new Case();
                tempCase.setCaseStatusCode(new CodeService().getCodeForKeyGroup("ACTIVE","CASE_STATUS"));
                caseService.saveCase(tempCase, tenantId);
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                caseNum2 = new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);

            }
        }).start();

        String caseNumbers = "{case1: " + caseNum1 + ", case2:" + caseNum2  + "}" ;

        return caseNumbers;
    }
}

但是 caseNum1 和 caseNum2 返回 null。知道为什么吗?也许 run() 没有被正确调用。虽然,我什至不确定我是否正确地执行此线程。有什么想法吗?

【问题讨论】:

  • 要在完全同时启动线程,请查看this
  • 看起来您要将其作为 Web 服务运行。您可能需要重新考虑使用实例变量,因为您可能有多个并发请求

标签: java multithreading hibernate


【解决方案1】:

试试这个:

    ...

    CountDownLatch latch = new CountDownLatch(2);


    new Thread(new Runnable() {
        public void run() {
            caseNum1= new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);
            Case tempCase = new Case();
            tempCase.setCaseStatusCode(new CodeService().getCodeForKeyGroup("ACTIVE","CASE_STATUS"));
            caseService.saveCase(tempCase, tenantId);
            latch.countDown();
        }
    }).start();

    new Thread(new Runnable() {
        public void run() {
            caseNum2 = new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);
            latch.countDown();

        }
    }).start();

    latch.await();

    ...

【讨论】:

  • 代码仍然不是线程安全的,因为变量不是易失的/同步的,所以不能保证工作
  • 不正确 - CountDownLatch 提供了必要的保证,请参阅 docs.oracle.com/javase/8/docs/api/java/util/concurrent/…
  • 你是对的。可能值得明确提及。
  • 也许,另一方面,util.concurrent 中的所有线程协调结构都是这样的。
【解决方案2】:

我可以看到的几个问题:

  1. 您的代码不是线程安全的。不能保证来自您创建的任何一个线程的写入都会在父线程中看到。您需要同步您的操作或使字段易变
  2. 在线程上调用 start() 后继续执行。线程并行执行。因此,在子线程中的写入和父线程中的读取之间存在竞争条件。您需要在父线程和子线程之间进行协调,例如通过调用它们的 join()。

【讨论】:

    【解决方案3】:

    您必须等待线程终止,否则代码将在线程填充值之前运行。当你运行一个新线程时,计算会继续,执行顺序是未知的。因此,您的主线程可能会在 t1t2 实际计算出值之前返回。

     Thread t1 = new Thread(new Runnable() {
           public void run() {
                    caseNum1= new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);
                    Case tempCase = new Case();
                    tempCase.setCaseStatusCode(new CodeService().getCodeForKeyGroup("ACTIVE","CASE_STATUS"));
                    caseService.saveCase(tempCase, tenantId);
                }
            });
    
     t1.start();
    
     Thread t2 = new Thread(new Runnable() {
            public void run() {
                caseNum2 = new CaseHelper(new ConfigurationService(),new CaseService()).getNextCaseNumberFromDatabase(tenantId);
    
            }
        });
    t2.start();
    
    t1.join();
    t2.join();
    
    String caseNumbers = "{case1: " + caseNum1 + ", case2:" + caseNum2  + "}" ;
    

    【讨论】:

    • 当我尝试 Thread t1 = new Thread(new Runnable() 时,它说它需要 java.lang.Thread 并且它发现了一个 void。有什么想法吗?
    • 对不起,我没有注意到末尾的 start()。首先创建线程对象,然后运行它们。
    【解决方案4】:

    您应该查看 servlet 3.0 异步操作。 在这种情况下,您可以在完成异步操作之前阻止响应提交。

    从春天看这个博客: https://spring.io/blog/2012/05/07/spring-mvc-3-2-preview-introducing-servlet-3-async-support

    【讨论】:

      【解决方案5】:

      我认为好的方法是使用Feature。在下面的示例中,您在并行线程中运行两个任务,并且您仍然有工作异常,就像在您的单线程示例中一样。

      public String getNextCaseNumber(String tenantId) throws Exception {
          ExecutorService executor = Executors.newFixedThreadPool(2);
          Future<String> caseNum1 = executor.submit(() -> {
              String caseNum = new CaseHelper(new ConfigurationService(), new CaseService()).getNextCaseNumberFromDatabase(tenantId);
              Case tempCase = new Case();
              tempCase.setCaseStatusCode(new CodeService().getCodeForKeyGroup("ACTIVE", "CASE_STATUS"));
              caseService.saveCase(tempCase, tenantId);
              return caseNum;
          });
          Future<String> caseNum2 = executor.submit(() -> new CaseHelper(new ConfigurationService(), new CaseService()).getNextCaseNumberFromDatabase(tenantId));
      
          return String.format("{case1: %s, case2: %s}", caseNum1.get(), caseNum2.get());
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-27
        • 1970-01-01
        相关资源
        最近更新 更多