Do these threads started from a loop execute asynchronously? - java

My data size is huge so I thought of dividing it into chunks and using threads to process it asynchronously.
To make it simple let's say I have a list and associate each entry with a thread, so the number of threads is equal to the number of elements. Since I am new to threads in Java so I am not sure how the threads run asynchronously. Here is a simplified code for better understanding.
class ThreadRunner extends Thread {
String threadName;
String element;
public MyThread (String threadName, String element) {
this.threadName = threadName;
this.element = element;
}
public void run() {
System.out.println("Run: "+ threadName);
// some processing on the item
}
}
class TestThread {
public static void main (String arg[]) {
List<String> mainList = new ArrayList<>();
for (int x=0; x< mainList.size(); x++)
{
MyThread temp= new MyThread("Thread #" + x+1);
temp.start();
System.out.println("Started Thread:" + x+1);
}
}
Does this code execute the threads in an asynchronous manner?

Instead of spawning threads yourself, use an ExecutorService and submit work to it in the form of Runnables.
Each Runnable task should process enough work to justify the overhead of spawning threads but not so much work that you underutilize the other cores. In other words, you want to properly load balance the work across your cores. One way to do this is to divide the elements evenly across the tasks so that each task processes roughly num_threads / mainList.size()elements and you submit num_thread tasks to the ExecutorService.

Related

I want to stop a group of completed threads, wait for uncompleted threads

I need a group of threads to run at the same time, and then another group of threads after that. For example, 10 threads start working, and then 10 or 15 other threads.
Of course, the first approach I've tried was to create a loop.
while (true) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(
new Runnable() {
#Override
public void run() {
System.out.println("hi");
}
});
thread.start();
}
}
But the problem is when scenario like this happens: imagine if in first iteration, 8 threads finished their tasks, and 2 threads take longer time. The next 10 threads won't start until all 8 + 2 (completed and not completed) threads finish. while, I want an approach where 8 threads get replaced by 8 of waiting to start threads.
Bare Threads
It can be done using bare Thread and Runnable without diving into more advance technologies.
For that, you need to perform the following steps:
define your task (provide an implementation of the Runnable interface);
generate a collection of Threads creating based on this task);
start every thread;
invoke join() on every of these thread (note that firstly we need to start all threads).
That's how it might look like:
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> System.out.println("hi");
int counter = 0;
while (true) {
System.out.println("iteration: " + counter++);
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(task));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
Thread.currentThread().sleep(1000);
}
}
Instead of managing your Threads manually, it definitely would be wise to look at the facilities provided by the implementations of the ExecutorService interfaces.
Things would be a bit earthier if you use Callable interface for your task instead of Runnable. Callable is more handy in many cases because it allows obtaining the result from the worker-thread and also propagating an exception if thing went wrong (as opposed run() would force you to catch every checked exception). If you have in mind something more interesting than printing a dummy message, you might find Callable to be useful for your purpose.
ExecutorService.invokeAll() + Callable
ExecutorService has a blocking method invokeAll() which expects a collection of the callable-tasks and return a list of completed Future objects when all the tasks are done.
To generate a light-weight collection of repeated elements (since we need to fire a bunch of identical tasks) we can use utility method Collections.nCopies().
Here's a sample code which repeatedly runs a dummy task:
ExecutorService executor = Executors.newWorkStealingPool();
while (true) {
executor.invokeAll(Collections.nCopies(10, () -> {
System.out.println("hi");
return true;
}));
}
To make sure that it does what expected, we can add a counter of iterations and display it on the console and Thread.currentThread().sleep() to avoid cluttering the output very fast (for the same reason, the number of tasks reduced to 3):
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newWorkStealingPool();
int counter = 0;
while (true) {
System.out.println("iteration: " + counter++);
executor.invokeAll(Collections.nCopies(3, () -> {
System.out.println("hi");
return true;
}));
Thread.currentThread().sleep(1000);
}
}
Output:
iteration: 0
hi
hi
hi
iteration: 1
hi
hi
hi
... etc.
CompletableFuture.allOf().join() + Runnable
Another possibility is to use CompletableFuture API, and it's method allOf() which expects a varargs of submitted tasks in the form CompletableFuture and return a single CompletableFuture which would be completed when all provided arguments are done.
In order to synchronize the execution of the tasks with the main thread, we need to invoke join() on the resulting CompletableFuture instance.
That's how it might be implemented:
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newWorkStealingPool();
Runnable task = () -> System.out.println("hi");
int counter = 0;
while (true) {
System.out.println("iteration: " + counter++);
CompletableFuture.allOf(
Stream.generate(() -> task)
.limit(3)
.map(t -> CompletableFuture.runAsync(t, executor))
.toArray(CompletableFuture<?>[]::new)
).join();
Thread.currentThread().sleep(1000);
}
}
Output:
iteration: 0
hi
hi
hi
iteration: 1
hi
hi
hi
... etc.
ScheduledExecutorService
I suspect you might interested in scheduling these tasks instead of running them reputedly. If that's the case, have a look at ScheduledExecutorService and it's methods scheduleAtFixedRate() and scheduleWithFixedDelay().
For adding tasks to threads and replacing them you can use ExecutorService. You can create it by using:
ExecutorService executor = Executors.newFixedThreadPool(10);

Java Threadpool handle unlimited queued threads?

im testing my Server which has a threadpool for the connections.
public class Test
{
public static final void main(String[] args)
{
ThreadPoolExecutor threadPoolExecutorSentMessage = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
100,
5,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>());
ConnctionListener con = new ConnctionListener() //ignore this, included it for other usage.
{
public void onStartSendingMessages()
{
while(true)
{
for(int i = 0; i < 50; i++)
{
threadPoolExecutorSentMessage.execute(new TestT("Message: " + i));
}
}
}
};
con.onStartSendingMessages();
//new Thread(new MessageConnectionWaiter(con)).start();
}
private static class TestT implements Runnable
{
private String msg;
public TestT(String msg)
{
this.msg = msg;
}
#Override
public void run()
{
System.out.println(msg);
}
}
}
Its not the server code, but im testing with the code how the threads working.
When im starting unlimited threads(like many connections to my server), there is a problem, that its stuck and nothing happens. I though that the threadpool is blocking new tasks, before the threadpool has avaiable space for a new thread. Can someone tell how to handle something like this? I tried to reduce the amount of max. threads but it dont fixed my problem. I just want that the threadpool runs thread no matter how much threads are waiting.
This is not the number of threads causing the problem. It is the number of tasks you are adding to the workqueue. You are adding the tasks in a infinite loop. And work queue has a capacity, the linked queue has maximum capacity of Integer.MAX_VALUE. After you have added that many tasks, the main thread start waiting for the space to be emptied in work queue. After your threadpools thread complete execution of any task and removes the task from the queue, the space becomes available and main thread can add the task only if there is any space for the task in the queue

Java concurrency counter not properly clean up

This is a java concurrency question. 10 jobs need to be done, each of them will have 32 worker threads. Worker thread will increase a counter . Once the counter is 32, it means this job is done and then clean up counter map. From the console output, I expect that 10 "done" will be output, pool size is 0 and counterThread size is 0.
The issues are :
most of time, "pool size: 0 and countThreadMap size:3" will be
printed out. even those all threads are gone, but 3 jobs are not
finished yet.
some time, I can see nullpointerexception in line 27. I have used ConcurrentHashMap and AtomicLong, why still have concurrency
exception.
Thanks
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicLong;
public class Test {
final ConcurrentHashMap<Long, AtomicLong[]> countThreadMap = new ConcurrentHashMap<Long, AtomicLong[]>();
final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
final ThreadPoolExecutor tPoolExecutor = ((ThreadPoolExecutor) cachedThreadPool);
public void doJob(final Long batchIterationTime) {
for (int i = 0; i < 32; i++) {
Thread workerThread = new Thread(new Runnable() {
#Override
public void run() {
if (countThreadMap.get(batchIterationTime) == null) {
AtomicLong[] atomicThreadCountArr = new AtomicLong[2];
atomicThreadCountArr[0] = new AtomicLong(1);
atomicThreadCountArr[1] = new AtomicLong(System.currentTimeMillis()); //start up time
countThreadMap.put(batchIterationTime, atomicThreadCountArr);
} else {
AtomicLong[] atomicThreadCountArr = countThreadMap.get(batchIterationTime);
atomicThreadCountArr[0].getAndAdd(1);
countThreadMap.put(batchIterationTime, atomicThreadCountArr);
}
if (countThreadMap.get(batchIterationTime)[0].get() == 32) {
System.out.println("done");
countThreadMap.remove(batchIterationTime);
}
}
});
tPoolExecutor.execute(workerThread);
}
}
public void report(){
while(tPoolExecutor.getActiveCount() != 0){
//
}
System.out.println("pool size: "+ tPoolExecutor.getActiveCount() + " and countThreadMap size:"+countThreadMap.size());
}
public static void main(String[] args) throws Exception {
Test test = new Test();
for (int i = 0; i < 10; i++) {
Long batchIterationTime = System.currentTimeMillis();
test.doJob(batchIterationTime);
}
test.report();
System.out.println("All Jobs are done");
}
}
Let’s dig through all the mistakes of thread related programming, one man can make:
Thread workerThread = new Thread(new Runnable() {
…
tPoolExecutor.execute(workerThread);
You create a Thread but don’t start it but submit it to an executor. It’s a historical mistake of the Java API to let Thread implement Runnable for no good reason. Now, every developer should be aware, that there is no reason to treat a Thread as a Runnable. If you don’t want to start a thread manually, don’t create a Thread. Just create the Runnable and pass it to execute or submit.
I want to emphasize the latter as it returns a Future which gives you for free what you are attempting to implement: the information when a task has been finished. It’s even easier when using invokeAll which will submit a bunch of Callables and return when all are done. Since you didn’t tell us anything about your actual task, it’s not clear whether you can let your tasks simply implement Callable (may return null) instead of Runnable.
If you can’t use Callables or don’t want to wait immediately on submission, you have to remember the returned Futures and query them at a later time:
static final ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
public static List<Future<?>> doJob(final Long batchIterationTime) {
final Random r=new Random();
List<Future<?>> list=new ArrayList<>(32);
for (int i = 0; i < 32; i++) {
Runnable job=new Runnable() {
public void run() {
// pretend to do something
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(r.nextInt(10)));
}
};
list.add(cachedThreadPool.submit(job));
}
return list;
}
public static void main(String[] args) throws Exception {
Test test = new Test();
Map<Long,List<Future<?>>> map=new HashMap<>();
for (int i = 0; i < 10; i++) {
Long batchIterationTime = System.currentTimeMillis();
while(map.containsKey(batchIterationTime))
batchIterationTime++;
map.put(batchIterationTime,doJob(batchIterationTime));
}
// print some statistics, if you really need
int overAllDone=0, overallPending=0;
for(Map.Entry<Long,List<Future<?>>> e: map.entrySet()) {
int done=0, pending=0;
for(Future<?> f: e.getValue()) {
if(f.isDone()) done++;
else pending++;
}
System.out.println(e.getKey()+"\t"+done+" done, "+pending+" pending");
overAllDone+=done;
overallPending+=pending;
}
System.out.println("Total\t"+overAllDone+" done, "+overallPending+" pending");
// wait for the completion of all jobs
for(List<Future<?>> l: map.values())
for(Future<?> f: l)
f.get();
System.out.println("All Jobs are done");
}
But note that if you don’t need the ExecutorService for subsequent tasks, it’s much easier to wait for all jobs to complete:
cachedThreadPool.shutdown();
cachedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("All Jobs are done");
But regardless of how unnecessary the manual tracking of the job status is, let’s delve into your attempt, so you may avoid the mistakes in the future:
if (countThreadMap.get(batchIterationTime) == null) {
The ConcurrentMap is thread safe, but this does not turn your concurrent code into sequential one (that would render multi-threading useless). The above line might be processed by up to all 32 threads at the same time, all finding that the key does not exist yet so possibly more than one thread will then be going to put the initial value into the map.
AtomicLong[] atomicThreadCountArr = new AtomicLong[2];
atomicThreadCountArr[0] = new AtomicLong(1);
atomicThreadCountArr[1] = new AtomicLong(System.currentTimeMillis());
countThreadMap.put(batchIterationTime, atomicThreadCountArr);
That’s why this is called the “check-then-act” anti-pattern. If more than one thread is going to process that code, they all will put their new value, being confident that this was the right thing as they have checked the initial condition before acting but for all but one thread the condition has changed when acting and they are overwriting the value of a previous put operation.
} else {
AtomicLong[] atomicThreadCountArr = countThreadMap.get(batchIterationTime);
atomicThreadCountArr[0].getAndAdd(1);
countThreadMap.put(batchIterationTime, atomicThreadCountArr);
Since you are modifying the AtomicInteger which is already stored into the map, the put operation is useless, it will put the very array that it retrieved before. If there wasn’t the mistake that there can be multiple initial values as described above, the put operation had no effect.
}
if (countThreadMap.get(batchIterationTime)[0].get() == 32) {
Again, the use of a ConcurrentMap doesn’t turn the multi-threaded code into sequential code. While it is clear that the only last thread will update the atomic integer to 32 (when the initial race condition doesn’t materialize), it is not guaranteed that all other threads have already passed this if statement. Therefore more than one, up to all threads can still be at this point of execution and see the value of 32. Or…
System.out.println("done");
countThreadMap.remove(batchIterationTime);
One of the threads which have seen the 32 value might execute this remove operation. At this point, there might be still threads not having executed the above if statement, now not seeing the value 32 but producing a NullPointerException as the array supposed to contain the AtomicInteger is not in the map anymore. This is what happens, occasionally…
After creating your 10 jobs, your main thread is still running - it doesn't wait for your jobs to complete before it calls report on the test. You try to overcome this with the while loop, but tPoolExecutor.getActiveCount() is potentially coming out as 0 before the workerThread is executed, and then the countThreadMap.size() is happening after the threads were added to your HashMap.
There are a number of ways to fix this - but I will let another answer-er do that because I have to leave at the moment.

How to Synchronize Threads

In this multithreading program, when I run it, I always get the output in some random order. But I was wondering if there is any way I can make this program to work in synchronized mode. Like when I runt it then for the first thread it should print out everything, then for second thread it should print out something, then for third thread it should print out everything etc etc. So sample output should be like this for each thread-
Task 1 Started
original: Hello World
Difference:- 0
Task 1 Ended
Task 2 Started
original: Hello World
Difference:- 0
Task 2 Ended
............
............
Task 15 Started
original: Hello World
Difference:- 0
Task 15 Ended
This is my below program. Any suggestions will be appreciated.
class ThreadTask implements Runnable {
private int id;
public ThreadTask(int id) {
this.id = id;
}
public synchronized void run() {
System.out.println("Task " + id + " Started ");
String originalString = "Hello World";
System.out.println("original: " + originalString);
System.out.println("Task " + id + " Ended ");
}
}
public class TestPool {
public static void main(String[] args) throws InterruptedException {
int size = 5; //Integer.parseInt(args[0]);
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(size);
// queue some tasks
for(int i = 1; i <= 3 * size; i++) {
service.submit(new ThreadTask(i));
}
// wait for termination
service.shutdown();
service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
}
You commented on Jakub's answer as follows:
Can you give me example basis on my code as I just started learning about threading. It will be of great help to me.
What Jakub is saying is that forcing threads to run in a fixed sequence defeats the purpose of using threads in the first place. Think about this.
If you really do want / need your example to run the tasks in order, you may as well do this:
for (int i = 1; i <= 3 * size; i++) {
new ThreadTask(i).run();
}
i.e. just run the runnables in the current thread.
Or you could set the maximum pool size to 1, which forces the service to run the tasks in order. (Of course, this defeats the point of using threads. You won't get any parallelism this way.)
A more sensible approach would be to have each thread return its results in a Future, and then have the main thread fetch the value from each future (in the required order) and print it. Basically, you want to allow the threads to run in any order (and in parallel, if you have multiple cores), but then impose the ordering when you access the results.
The essence of thread is that they can run simultaneously, if you want them to run in order, simply do not use Thread.
There's another kind of requirement, that maybe you want several jobs to work together (simultaneously), but in a given order. In this case, I highly suggest you to implement a queuing system. That is, build a queue like
Queue <C> q
And a thread
class T implements Runnable {
public void run() {
while (!q.empty()) {
// Do something
}
}
}
You can use Runnable through ExecutorService, like the code that you've used.
You can also add some elements into the queue in "Do something" section of previous code, then you can control the order of jobs by yourself.
You can save the the reference to the previous thread and hook up the next thread to the previous one using join(). That will ensure the threads will be run in a series (next one not starting unless the previous one finished). But the point of doing that is eluding me.
public class TestPool
{
static class ThreadTask extends Thread
{
private int id;
private Thread previous;
public ThreadTask(int id, Thread previous){
this.id = id;
this.previous = previous;
}
public void run(){
if(previous != null){
try{
previous.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("Task " + id + " Started ");
String originalString = "Hello World";
System.out.println("original: " + originalString);
System.out.println("Task " + id + " Ended ");
}
}
public static void main(String[] args) throws InterruptedException{
int size = 5; // Integer.parseInt(args[0]);
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(size);
Thread previous = null;
// queue some tasks
for(int i = 1; i <= 3 * size; i++){
Thread thread = new ThreadTask(i, previous);
previous = thread;
thread.start();
//service.submit(thread);
}
// wait for termination
//service.shutdown();
//service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
}
Not tested, sry. I don't also know what the ExecutorService is doing, it might break this. Note that I need to be a Thread, being Runnable is not enough. Also, run() needs not be synchronised, as it will be called only once per execution. And you should not start the threads with run(), but with start().
EDIT: I just tried to run it, and the ExecutorService is fu**ing things up. If you just start the thread (like the my code does), then it's working.

Is it possible to use multithreading without creating Threads over and over again?

First and once more, thanks to all that already answered my question. I am not a very experienced programmer and it is my first experience with multithreading.
I got an example that is working quite like my problem. I hope it could ease our case here.
public class ThreadMeasuring {
private static final int TASK_TIME = 1; //microseconds
private static class Batch implements Runnable {
CountDownLatch countDown;
public Batch(CountDownLatch countDown) {
this.countDown = countDown;
}
#Override
public void run() {
long t0 =System.nanoTime();
long t = 0;
while(t<TASK_TIME*1e6){ t = System.nanoTime() - t0; }
if(countDown!=null) countDown.countDown();
}
}
public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadFactory() {
int counter = 1;
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Executor thread " + (counter++));
return t;
}
};
// the total duty to be divided in tasks is fixed (problem dependent).
// Increase ntasks will mean decrease the task time proportionally.
// 4 Is an arbitrary example.
// This tasks will be executed thousands of times, inside a loop alternating
// with serial processing that needs their result and prepare the next ones.
int ntasks = 4;
int nthreads = 2;
int ncores = Runtime.getRuntime().availableProcessors();
if (nthreads<ncores) ncores = nthreads;
Batch serial = new Batch(null);
long serialTime = System.nanoTime();
serial.run();
serialTime = System.nanoTime() - serialTime;
ExecutorService executor = Executors.newFixedThreadPool( nthreads, threadFactory );
CountDownLatch countDown = new CountDownLatch(ntasks);
ArrayList<Batch> batches = new ArrayList<Batch>();
for (int i = 0; i < ntasks; i++) {
batches.add(new Batch(countDown));
}
long start = System.nanoTime();
for (Batch r : batches){
executor.execute(r);
}
// wait for all threads to finish their task
try {
countDown.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long tmeasured = (System.nanoTime() - start);
System.out.println("Task time= " + TASK_TIME + " ms");
System.out.println("Number of tasks= " + ntasks);
System.out.println("Number of threads= " + nthreads);
System.out.println("Number of cores= " + ncores);
System.out.println("Measured time= " + tmeasured);
System.out.println("Theoretical serial time= " + TASK_TIME*1000000*ntasks);
System.out.println("Theoretical parallel time= " + (TASK_TIME*1000000*ntasks)/ncores);
System.out.println("Speedup= " + (serialTime*ntasks)/(double)tmeasured);
executor.shutdown();
}
}
Instead of doing the calculations, each batch just waits for some given time. The program calculates the speedup, that would allways be 2 in theory but can get less than 1 (actually a speed down) if the 'TASK_TIME' is small.
My calculations take at the top 1 ms and are commonly faster. For 1 ms I find a little speedup of around 30%, but in practice, with my program, I notice a speed down.
The structure of this code is very similar to my program, so if you could help me to optimise the thread handling I would be very grateful.
Kind regards.
Below, the original question:
Hi.
I would like to use multithreading on my program, since it could increase its efficiency considerably, I believe. Most of its running time is due to independent calculations.
My program has thousands of independent calculations (several linear systems to solve), but they just happen at the same time by minor groups of dozens or so. Each of this groups would take some miliseconds to run. After one of these groups of calculations, the program has to run sequentially for a little while and then I have to solve the linear systems again.
Actually, it can be seen as these independent linear systems to solve are inside a loop that iterates thousands of times, alternating with sequential calculations that depends on the previous results. My idea to speed up the program is to compute these independent calculations in parallel threads, by dividing each group into (the number of processors I have available) batches of independent calculation. So, in principle, there isn't queuing at all.
I tried using the FixedThreadPool and CachedThreadPool and it got even slower than serial processing. It seems to takes too much time creating new Treads each time I need to solve the batches.
Is there a better way to handle this problem? These pools I've used seem to be proper for cases when each thread takes more time instead of thousands of smaller threads...
Thanks!
Best Regards!
Thread pools don't create new threads over and over. That's why they're pools.
How many threads were you using and how many CPUs/cores do you have? What is the system load like (normally, when you execute them serially, and when you execute with the pool)? Is synchronization or any kind of locking involved?
Is the algorithm for parallel execution exactly the same as the serial one (your description seems to suggest that serial was reusing some results from previous iteration).
From what i've read: "thousands of independent calculations... happen at the same time... would take some miliseconds to run" it seems to me that your problem is perfect for GPU programming.
And i think it answers you question. GPU programming is becoming more and more popular. There are Java bindings for CUDA & OpenCL. If it is possible for you to use it, i say go for it.
I'm not sure how you perform the calculations, but if you're breaking them up into small groups, then your application might be ripe for the Producer/Consumer pattern.
Additionally, you might be interested in using a BlockingQueue. The calculation consumers will block until there is something in the queue and the block occurs on the take() call.
private static class Batch implements Runnable {
CountDownLatch countDown;
public Batch(CountDownLatch countDown) {
this.countDown = countDown;
}
CountDownLatch getLatch(){
return countDown;
}
#Override
public void run() {
long t0 =System.nanoTime();
long t = 0;
while(t<TASK_TIME*1e6){ t = System.nanoTime() - t0; }
if(countDown!=null) countDown.countDown();
}
}
class CalcProducer implements Runnable {
private final BlockingQueue queue;
CalcProducer(BlockingQueue q) { queue = q; }
public void run() {
try {
while(true) {
CountDownLatch latch = new CountDownLatch(ntasks);
for(int i = 0; i < ntasks; i++) {
queue.put(produce(latch));
}
// don't need to wait for the latch, only consumers wait
}
} catch (InterruptedException ex) { ... handle ...}
}
CalcGroup produce(CountDownLatch latch) {
return new Batch(latch);
}
}
class CalcConsumer implements Runnable {
private final BlockingQueue queue;
CalcConsumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while(true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Batch batch) {
batch.Run();
batch.getLatch().await();
}
}
class Setup {
void main() {
BlockingQueue<Batch> q = new LinkedBlockingQueue<Batch>();
int numConsumers = 4;
CalcProducer p = new CalcProducer(q);
Thread producerThread = new Thread(p);
producerThread.start();
Thread[] consumerThreads = new Thread[numConsumers];
for(int i = 0; i < numConsumers; i++)
{
consumerThreads[i] = new Thread(new CalcConsumer(q));
consumerThreads[i].start();
}
}
}
Sorry if there are any syntax errors, I've been chomping away at C# code and sometimes I forget the proper java syntax, but the general idea is there.
If you have a problem which does not scale to multiple cores, you need to change your program or you have a problem which is not as parallel as you think. I suspect you have some other type of bug, but cannot say based on the information given.
This test code might help.
Time per million tasks 765 ms
code
ExecutorService es = Executors.newFixedThreadPool(4);
Runnable task = new Runnable() {
#Override
public void run() {
// do nothing.
}
};
long start = System.nanoTime();
for(int i=0;i<1000*1000;i++) {
es.submit(task);
}
es.shutdown();
es.awaitTermination(10, TimeUnit.SECONDS);
long time = System.nanoTime() - start;
System.out.println("Time per million tasks "+time/1000/1000+" ms");
EDIT: Say you have a loop which serially does this.
for(int i=0;i<1000*1000;i++)
doWork(i);
You might assume that changing to loop like this would be faster, but the problem is that the overhead could be greater than the gain.
for(int i=0;i<1000*1000;i++) {
final int i2 = i;
ex.execute(new Runnable() {
public void run() {
doWork(i2);
}
}
}
So you need to create batches of work (at least one per thread) so there are enough tasks to keep all the threads busy, but not so many tasks that your threads are spending time in overhead.
final int batchSize = 10*1000;
for(int i=0;i<1000*1000;i+=batchSize) {
final int i2 = i;
ex.execute(new Runnable() {
public void run() {
for(int i3=i2;i3<i2+batchSize;i3++)
doWork(i3);
}
}
}
EDIT2: RUnning atest which copied data between threads.
for (int i = 0; i < 20; i++) {
ExecutorService es = Executors.newFixedThreadPool(1);
final double[] d = new double[4 * 1024];
Arrays.fill(d, 1);
final double[] d2 = new double[4 * 1024];
es.submit(new Runnable() {
#Override
public void run() {
// nothing.
}
}).get();
long start = System.nanoTime();
es.submit(new Runnable() {
#Override
public void run() {
synchronized (d) {
System.arraycopy(d, 0, d2, 0, d.length);
}
}
});
es.shutdown();
es.awaitTermination(10, TimeUnit.SECONDS);
// get a the values in d2.
for (double x : d2) ;
long time = System.nanoTime() - start;
System.out.printf("Time to pass %,d doubles to another thread and back was %,d ns.%n", d.length, time);
}
starts badly but warms up to ~50 us.
Time to pass 4,096 doubles to another thread and back was 1,098,045 ns.
Time to pass 4,096 doubles to another thread and back was 171,949 ns.
... deleted ...
Time to pass 4,096 doubles to another thread and back was 50,566 ns.
Time to pass 4,096 doubles to another thread and back was 49,937 ns.
Hmm, CachedThreadPool seems to be created just for your case. It does not recreate threads if you reuse them soon enough, and if you spend a whole minute before you use new thread, the overhead of thread creation is comparatively negligible.
But you can't expect parallel execution to speed up your calculations unless you can also access data in parallel. If you employ extensive locking, many synchronized methods, etc you'll spend more on overhead than gain on parallel processing. Check that your data can be efficiently processed in parallel and that you don't have non-obvious synchronizations lurkinb in the code.
Also, CPUs process data efficiently if data fully fit into cache. If data sets of each thread is bigger than half the cache, two threads will compete for cache and issue many RAM reads, while one thread, if only employing one core, may perform better because it avoids RAM reads in the tight loop it executes. Check this, too.
Here's a psuedo outline of what I'm thinking
class WorkerThread extends Thread {
Queue<Calculation> calcs;
MainCalculator mainCalc;
public void run() {
while(true) {
while(calcs.isEmpty()) sleep(500); // busy waiting? Context switching probably won't be so bad.
Calculation calc = calcs.pop(); // is it pop to get and remove? you'll have to look
CalculationResult result = calc.calc();
mainCalc.returnResultFor(calc,result);
}
}
}
Another option, if you're calling external programs. Don't put them in a loop that does them one at a time or they won't run in parallel. You can put them in a loop that PROCESSES them one at a time, but not that execs them one at a time.
Process calc1 = Runtime.getRuntime.exec("myCalc paramA1 paramA2 paramA3");
Process calc2 = Runtime.getRuntime.exec("myCalc paramB1 paramB2 paramB3");
Process calc3 = Runtime.getRuntime.exec("myCalc paramC1 paramC2 paramC3");
Process calc4 = Runtime.getRuntime.exec("myCalc paramD1 paramD2 paramD3");
calc1.waitFor();
calc2.waitFor();
calc3.waitFor();
calc4.waitFor();
InputStream is1 = calc1.getInputStream();
InputStreamReader isr1 = new InputStreamReader(is1);
BufferedReader br1 = new BufferedReader(isr1);
String resultStr1 = br1.nextLine();
InputStream is2 = calc2.getInputStream();
InputStreamReader isr2 = new InputStreamReader(is2);
BufferedReader br2 = new BufferedReader(isr2);
String resultStr2 = br2.nextLine();
InputStream is3 = calc3.getInputStream();
InputStreamReader isr3 = new InputStreamReader(is3);
BufferedReader br3 = new BufferedReader(isr3);
String resultStr3 = br3.nextLine();
InputStream is4 = calc4.getInputStream();
InputStreamReader isr4 = new InputStreamReader(is4);
BufferedReader br4 = new BufferedReader(isr4);
String resultStr4 = br4.nextLine();

Categories

Resources