17

Problem description : -

Step 1: Take input FILE_NAME from user at main thread.

Step 2: Perform 10 operations on that file (i.e count chars, count lines etc.. ), and all those 10 operations must be in septate threads. It means there must be 10 child threads.

Step 3: Main thread waits until all those child threads completed.

Step 4: Print result.

What I did :-

I did a sample code with 3 threads. I don't want file operation code from your side.

public class ThreadTest {
    // This is object to synchronize on.
    private static final Object waitObject = ThreadTest.class;
    // Your boolean.
    private static boolean boolValue = false;

    public final Result result = new Result();

    public static void main(String[] args) {
        final ThreadTest mytest = new ThreadTest();

        System.out.println("main started");

        new Thread(new Runnable() {

            public void run() {
                System.out.println("Inside thread");

                //Int initialiser
                new Thread(new Runnable() {

                    public void run() {
                        System.out.println("Setting integer value");
                        mytest.result.setIntValue(346635);
                        System.out.println("Integer value seted");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }).start();

                //String initialiser
                new Thread(new Runnable() {

                    public void run() {
                        System.out.println("Setting string value");
                        mytest.result.setStringValue("Hello hi");
                        System.out.println("String value seted");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }).start();

                //Boolean initialiser
                new Thread(new Runnable() {

                    public void run() {
                        System.out.println("Setting boolean value");
                        mytest.result.setBoolValue(true);
                        System.out.println("Boolean value seted");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }).start();

                System.out.println("Thread is finished");

                //Notify to main thread
                synchronized (ThreadTest.waitObject) {
                    ThreadTest.boolValue = true;
                    ThreadTest.waitObject.notifyAll();
                }               
            }
        }).start();

        try {
            synchronized (ThreadTest.waitObject) {
                while (!ThreadTest.boolValue) {
                    ThreadTest.waitObject.wait();
                }
            }
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }

        System.out.println("main finished");
        System.out.println("Result is : " + mytest.result.toString());
    }
}

Problem :-

My above code is not giving correct answer. How can I do that?

Alternate solutions:

CountDownLatch class does the same. But I don't want to use that class.

I looked this similar solution and I want to use methods of Thread only.

Community
  • 1
  • 1
Andy
  • 203
  • 1
  • 3
  • 8

6 Answers6

43

You can do:

Thread t = new Thread() {
    public void run() {
        System.out.println("text");
        // other complex code
    }
 };
 t.start();
 t.join();

This way you will wait until the thread finishes and just then continue. You can join multiple threads:

for (Thread thread : threads) {
  thread.join();
}
Boris Strandjev
  • 46,145
  • 15
  • 108
  • 135
  • Is join() is only solution? Or by modifying some code in my given example I can do that? – Andy Mar 30 '12 at 08:28
  • It is the best, most correct and advisable solution. Probably you can do it in other way, but I warn you - dealing with threads is tedious and reside to library functions as much as you can. – Boris Strandjev Mar 30 '12 at 08:31
  • 2
    I tried this but one thread waits the other thread for starting to execute. All threads are not executing in the same time. I want to start all threads and waits until all of them are finished. – Günay Gültekin Jun 24 '13 at 22:06
  • @GünayGültekin do you call all starts before all joins? – Boris Strandjev Jun 25 '13 at 06:56
  • I have a "for" loop. Each iterate creates a thread and start it and then I add ".join()". However the new threads waits previous thread for executing according to this what is the difference without generating threads in each loop. On the other hand, If I dont use ".join()", how could threads waits until all of them are finished ? – Günay Gültekin Jun 25 '13 at 10:14
  • 7
    @GünayGültekin construct all the threads in a for loop and call their `start` method. However do NOT call `join` in this loop - after the first join the main thread will wait for the first thread to finish and will just then start the second. After the first for loop do a second one that just call `join` on all threads at this point it is ok to wait for them as all of them are already started – Boris Strandjev Jun 25 '13 at 10:23
  • In addition, I use this in **doInBackground** function in AsyncTask on my android mobile app[link](http://developer.android.com/reference/android/os/AsyncTask.html). I send requests to web sites and collect data in mean time, I show loading effects to user in UI. When I use thread, **onPostExecute** is called immediately after executing **doInBackground**. In onPostExecute , I show the data on UI therefore no results are shown however the threads still continues. May be I am wrong to use both AsyncTask and Thread at the same time? What do you think? – Günay Gültekin Jun 25 '13 at 10:51
  • @GünayGültekin: AsyncTasks have one more method that you might have not heard about: this is onProgressUpdate: http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...). If i get your case correctly this will be interesting to you. – Boris Strandjev Jun 25 '13 at 10:57
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/32331/discussion-between-gunay-gultekin-and-boris-strandjev) – Günay Gültekin Jun 25 '13 at 11:14
  • Calling `t.join()` is probably wrong since **Thread t won't run in parallel**. Instead use [ExecutorService](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html) - see this answer: http://stackoverflow.com/a/7939499/516418 – stuchl4n3k Sep 14 '14 at 11:19
12

I would recommend looking at the Executors framework first, and then look into the CompletionService.

Then you can write something like this:

ExecutorService executor = Executors.newFixedThreadPool(maxThreadsToUse);
CompletionService completion = new ExecutorCompletionService(executor);
for (each sub task) {
    completion.submit(new SomeTaskYouCreate())
}
// wait for all tasks to complete.
for (int i = 0; i < numberOfSubTasks; ++i) {
     completion.take(); // will block until the next sub task has completed.
}
executor.shutdown();
daveb
  • 74,111
  • 6
  • 45
  • 51
  • thank you for specifying the completionservice..Was looking for it from past 1 day :) – xyz Nov 18 '15 at 03:48
  • @daveb what happens if we don't use the second for loop. if we implement that second for loop will all sub tasks run in parallel – harsha kumar Reddy Jun 12 '20 at 13:02
  • this solutions blocked the main thread until it finished. How can you make it execute in background and get result of completion? – CanCoder Aug 14 '20 at 15:05
4

In Java 8 a far better approach is to use parallelStream()

Note: it is far easier to see exactly what these background tasks are doing.

public static void main(String[] args) {
    Stream.<Runnable>of(
         () -> mytest.result.setIntValue(346635),
         () -> mytest.result.setStringValue("Hello hi"),
         () -> mytest.result.setBoolValue(true) )
         .parallel()
         .forEach(Runnable::run);

    System.out.println("main finished");
    System.out.println("Result is : " + mytest.result.toString());
}

I took out the debug information and the sleep as these don't alter the outcome.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
3

You may want to choose CountDownLatch from java.util.concurrent. From JavaDocs:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

Sample code:

import java.util.concurrent.CountDownLatch;

public class Test {
    private final ChildThread[] children;
    private final CountDownLatch latch;

    public Test() {
        this.children = new ChildThread[4];
        this.latch = new CountDownLatch(children.length);
        children[0] = new ChildThread(latch, "Task 1");
        children[1] = new ChildThread(latch, "Task 2");
        children[2] = new ChildThread(latch, "Task 3");
        children[3] = new ChildThread(latch, "Task 4");
    }

    public void run() {
        startChildThreads();
        waitForChildThreadsToComplete();
    }

    private void startChildThreads() {
        Thread[] threads = new Thread[children.length];

        for (int i = 0; i < threads.length; i++) {
            ChildThread child = children[i];
            threads[i] = new Thread(child);
            threads[i].start();
        }
    }

    private void waitForChildThreadsToComplete() {
        try {
            latch.await();
            System.out.println("All child threads have completed.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private class ChildThread implements Runnable {
        private final String name;
        private final CountDownLatch latch;

        protected ChildThread(CountDownLatch latch, String name) {
            this.latch = latch;
            this.name = name;
        }

        @Override
        public void run() {
            try {
                // Implementation
                System.out.println(name + " has completed.");
            } finally {
                latch.countDown();
            }
        }
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.run();
    }
}

Output:

Task 1 has completed. Task 4 has completed. Task 3 has completed. Task 2 has completed. All child threads have completed.

shapiy
  • 1,117
  • 12
  • 14
1

Check if all child threads are dead, every n seconds. Simple, yet effective method:

        boolean allDead=false;
        while(! allDead){
            allDead=true;
            for (int t = 0; t < threadCount; t++)
                if(threads[t].isAlive())    allDead=false;
            Thread.sleep(2000);

        }
Zuman
  • 41
  • 3
1

There are many ways to approach this. Consider CountDownLatch:

import java.util.concurrent.CountDownLatch;

public class WorkerTest {
    final int NUM_JOBS = 3;
    final CountDownLatch countDownLatch = new CountDownLatch(NUM_JOBS);
    final Object mutex = new Object(); 
    int workData = 0;

    public static void main(String[] args) throws Exception {
        WorkerTest workerTest = new WorkerTest();
        workerTest.go();
        workerTest.awaitAndReportData();
    }

    private void go() {
        for (int i = 0; i < NUM_JOBS; i++) {
            final int fI = i;
            Thread t = new Thread() {
                public void run() {
                    synchronized(mutex) {
                        workData++;
                    }
                    try {
                        Thread.sleep(fI * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    countDownLatch.countDown();
                }
            };
            t.start();
        }
    }

    private void awaitAndReportData() throws InterruptedException {
        countDownLatch.await();
        synchronized(mutex) {
            System.out.println("All workers done. workData=" + workData);
        }
    }
}
Mike Clark
  • 10,027
  • 3
  • 40
  • 54