3

I want to execute these two pieces of code at the same time. Here's the code I have so far:

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

Everything works here, but I am wanting to do the following tasks at the same time:

Task1: Output caseNum1, save new case to database

Task2: output caseNum2

Here's what I tried to do:

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

But caseNum1 and caseNum2 are returning null. Any idea why? Maybe run() is not being correctly called. Although, I am not even sure if I am doing this threading right. Any ideas?

lakeIn231
  • 1,177
  • 3
  • 14
  • 34
  • For starting threads at **Exactly** the same time look at [this](http://stackoverflow.com/questions/3376586/how-to-start-two-threads-at-exactly-the-same-time) – Dan Jan 20 '16 at 17:19
  • It looks as though you're going to run this as a web service. You might want to reconsider using instance variables as you might have multiple concurrent requests – user1675642 Jan 20 '16 at 17:54

5 Answers5

2

Try this:

    ...

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

    ...
David Soroko
  • 8,521
  • 2
  • 39
  • 51
0

You have to wait for the thread termination or the code will run before the thread have filled the values. When you run a new thread, the computation continues and the order of execution is not known. So your main thread might hit the return before t1 and t2 have actually calculated the values.

 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  + "}" ;
Simone Zandara
  • 9,401
  • 2
  • 19
  • 26
0

A couple of problems that I can see:

  1. Your code is not thread safe. There's no guarantee that writes from either of the Threads you create will be seen in the parent Thread. You need to synchronize what your doing or make the fields volatile
  2. Execution continues after you call start() on a Thread. The Thread executes in parallel. Therefore there's a race condition in your code between the writes in the child Thread and the reads in the parent Thread. You need coordination between your parent and child threads, eg by calling join() on them.
user1675642
  • 747
  • 2
  • 5
  • 15
0

You should look at servlet 3.0 async operations. In this case you can hold the response from committing until you have finished the async operation.

See this blog from spring: https://spring.io/blog/2012/05/07/spring-mvc-3-2-preview-introducing-servlet-3-async-support

Paul Arer
  • 183
  • 3
  • 5
0

I think that good approach is to use Feature. In example below, you run two tasks in parallel threads and you still have working Exception, just like in your single-thread example.

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());
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35