Executor suitable for non thread-safe code
Asked Answered
S

2

5

I am developing some code that will eventually be multithreaded, using a thread pool Executor. The tasks executed by the thread pool will make call-backs and (sometimes) submit further tasks to the task queue. I would like to develop the code single threaded first, get it right (I'm using Test Driven Development) and only then make the alterations to ensure thread safety (locks, etc). To do that, I need an Executor that is safe to use with non thread-safe code.

I think that means I need an Executor that is single-threaded. That is, it is causes all work to be done by the calling thread. Does the JRE provide such an Executor? Or is it possible to configure one of its Executors to operate in that mode?


I am already using the Humble Object testing pattern to test most of my code single-threaded. However, some of my code must interact with an Executor, or perhaps an ExecutorService, because it is about scheduling and resubmission of tasks, and it will do so in a non-trivial manner. Testing that code is the challenge here. The tasks update a shared object, which holds their results and input data. I want to delay having to make that shared object thread-safe until I have the scheduling and resubmission code implemented and debugged.

Subsolar answered 6/11, 2018 at 10:23 Comment(4)
will there be any communications between the caller and the thread from the pool?Cosmetic
I mean Executor is perfectly thread-safe, and it isn't going to interact with your threads if the tasks you are submitting don't do so. In other words, it all depends on the type of tasks you are giving to it.Cosmetic
I'm not sure if going for a single thread is the right approach here, you likely will have to change quite a lot later. Rather than executing everything in a single thread for now, I would rather try to go for a main thread + one worker thread running at a time. The main thread could call blocking methods to get the results of a task (e.g. Future.get). This should keep concurrency at minimum but you won't have to change your whole architecture later.Gallopade
Maybe Guava's MoreExecutors.html#sameThreadExecutor() ?Robinia
S
1

If the code really needs only an Executor, and not a (much more complex) ExecutorService, it is easy to implement your own single-threaded executor that does precisely what is needed. The API documentation of Executor even shows you how to do so:

class DirectExecutor implements Executor {
   public void execute(Runnable r) {
     r.run();
   }
}

If the code does need an ExecutorService, it is possible that the single thread executor provided byExecutors.newSingleThreadExecutor() is adequate for testing the non thread-safe code, despite the resulting program having two threads (the thread running the unit tests and the single thread-pool thread of the ExecutorService). This is because an ExecutorService must provide the following thread-safety guarantees:

  • Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task,
  • which in turn happen-before the result is retrieved via Future.get().

Therefore, if the thread running the unit tests does a Future.get() for all the submitted tasks, all changes to any shared objects will have been safely published, and the thread running the unit tests may safely examine those shared objects.

Subsolar answered 6/11, 2018 at 11:22 Comment(0)
U
2

If you plan to develop a single thread solution first than abstracting your business logic away from Thread semantics is the way to go. Implement a Callable or Runnable that you can test without starting a new Thread e.g. by using a mocked Executor in your unit tests.

Unworthy answered 6/11, 2018 at 10:33 Comment(1)
I'm already using the Humble Object pattern [question updated].Subsolar
S
1

If the code really needs only an Executor, and not a (much more complex) ExecutorService, it is easy to implement your own single-threaded executor that does precisely what is needed. The API documentation of Executor even shows you how to do so:

class DirectExecutor implements Executor {
   public void execute(Runnable r) {
     r.run();
   }
}

If the code does need an ExecutorService, it is possible that the single thread executor provided byExecutors.newSingleThreadExecutor() is adequate for testing the non thread-safe code, despite the resulting program having two threads (the thread running the unit tests and the single thread-pool thread of the ExecutorService). This is because an ExecutorService must provide the following thread-safety guarantees:

  • Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task,
  • which in turn happen-before the result is retrieved via Future.get().

Therefore, if the thread running the unit tests does a Future.get() for all the submitted tasks, all changes to any shared objects will have been safely published, and the thread running the unit tests may safely examine those shared objects.

Subsolar answered 6/11, 2018 at 11:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.