2016-01-20 2 views
3

Я хочу выполнить эти два фрагмента кода одновременно. Вот код, который я до сих пор:Выполнение двух задач одновременно в Java

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

Все здесь работает, но я хочу сделать следующие задачи одновременно:

TASK1: Выход caseNum1, сохранить новый случай в базу данных

Task2: выход 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; 
    } 
} 

Но случайNum1 и caseNum2 возвращают null. Любая идея почему? Возможно, run() неправильно вызван. Хотя, я даже не уверен, что я делаю эту правку. Есть идеи?

+0

Для запуска темы на ** ** Точно то же самое время смотреть на [это] (http://stackoverflow.com/questions/3376586/how-to-start-two-threads-at-exactly- то же время) – Dan

+0

Похоже, вы собираетесь запустить это как веб-сервис. Возможно, вы захотите пересмотреть использование переменных экземпляра, поскольку у вас может быть несколько одновременных запросов. – user1675642

ответ

2

Попробуйте это:

... 

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

    ... 
+0

Код по-прежнему не является потокобезопасным, поскольку переменные не являются изменчивыми/синхронизированными, поэтому это не гарантируется. – user1675642

+0

Неверно - CountDownLatch предоставляет необходимые гарантии, см. Https://docs.oracle.com/javase/8 /docs/api/java/util/concurrent/CountDownLatch.html –

+0

Вы правы. Не стоит упоминать это явно. – user1675642

0

Вам нужно дождаться окончания потока или код будет запущен до того, как поток заполнит значения. Когда вы запускаете новый поток, вычисление продолжается и порядок выполнения неизвестен. Таким образом, ваш основной поток может поразить результат до того, как t1 и t2 действительно рассчитали значения.

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 + "}" ; 
+0

Когда я пытаюсь использовать Thread t1 = new Thread (new Runnable(), он говорит, что для этого требуется java.lang.Thread, и он нашел пустоту. – Jay266

+0

Извините, я не заметил начала() в конце.Сначала создайте объект потока, а затем запустите их. –

0

несколько проблем, которые я вижу:

  1. Ваш код не поточно. Нет никакой гарантии, что записи из любого из создаваемых вами потоков будут видны в родительском потоке. Вам нужно синхронизировать то, что вы делаете, или сделать поля неустойчивыми.
  2. Выполнение продолжается после вызова start() в потоке. Поток выполняется параллельно. Поэтому в вашем коде есть состояние гонки между записью в дочернем потоке и чтением в родительском потоке. Вам нужна координация между родительским и дочерним потоками, например, путем вызова join() на них.
0

Я думаю, что хороший подход заключается в использовании Feature. В примере ниже вы запускаете две задачи в параллельных потоках и у вас все еще есть работа Exception, как и в примере с одним потоком.

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()); 
} 
Смежные вопросы