简体   繁体   中英

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

ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM