0

As we all know only one synchronized method can be run at the same time. So my questions is what if I declare the run() method as synchronized, and then run multi threads, is it possible for other thread to run the run() method? Like this:

public Test extends Thread
{
    public synchronized void run()
       {...do something}

}
Test thread1 = new Test();
Test thread2 = new Test();
thread1.start();
thread2.start();

Is it possible for thread2 to run or thread2 will wait thread1 to quit the run() method?

Radiodef
  • 37,180
  • 14
  • 90
  • 125
Spark8006
  • 635
  • 1
  • 7
  • 15

2 Answers2

4

The synchronized keyword on an instance method prevents concurrent calls of that method when called on the same instance.

Try the following (1):

class SynchTest {
    public static void main(String[] args) {
        // Note that we create a new Task each time.
        new Thread(new Task()).start();
        new Thread(new Task()).start();
        new Thread(new Task()).start();
    }

    static class Task implements Runnable {
        long start;

        Task() {
            this.start = System.currentTimeMillis();
        }

        @Override
        public synchronized void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignored) {
            }
            System.out.println(System.currentTimeMillis() - start);
        }
    }
}

That will output something like:

1000
1001
1001

In other words, the time elapsed for every task since its creation was about 1 second, so this means they were allowed to all run at the same time.

Now try the following (2):

class SynchTest {
    public static void main(String[] args) {
        // Now we pass the same instance each time.
        Task t = new Task();
        new Thread(t).start();
        new Thread(t).start();
        new Thread(t).start();
    }

    static class Task implements Runnable {
        long start;

        Task() {
            this.start = System.currentTimeMillis();
        }

        @Override
        public synchronized void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ignored) {
            }
            System.out.println(System.currentTimeMillis() - start);
        }
    }
}

Passing the same instance to all 3 threads means that the threads will try to call run on the same instance. This outputs something like the following:

1001
2001
3001

In other words, each task was made to wait for the previous one.

If you really want to synchronize all of run for every object, you can specify your own monitor object (3):

class SynchTest {
    public static void main(String[] args) {
        new Thread(new Task()).start();
        new Thread(new Task()).start();
        new Thread(new Task()).start();
    }

    static class Task implements Runnable {
        long start;

        Task() {
            this.start = System.currentTimeMillis();
        }

        static final Object STATIC_MONITOR = new Object();

        @Override
        public void run() {
            synchronized (STATIC_MONITOR) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ignored) {
                }
                System.out.println(System.currentTimeMillis() - start);
            }
        }
    }
}

That outputs the same as example 2, even though we create a new task every time.

See also: Should you synchronize the run method? Why or why not?

Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • 1
    The code implementation does not use the same runnable instance but new instances of SynchRun. I ran it but did not see the same results, but when same instance of runnable was passed did see the difference. – somshivam Aug 07 '16 at 15:54
2

You create two instance of Test as well as two threads run each, so it is impossible for other thread to run the run() method. Only if your two thread run with the same instance like this:

class CustomTask implements Runnable {
    private int number;
    public synchronized void run() {
        while(!Thread.currentThread().isInterrupted()){
            System.out.println(Thread.currentThread().getName() + ": " + number);
            Thread.yield();
            ++number;
        }   
    }   
}

public class ThreadTest {
    public static void main(String... args) throws Exception {
        CustomTask ct = new CustomTask();
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i = 0; i < 2; i++){
            exec.execute(ct);
        }   
        TimeUnit.MILLISECONDS.sleep(1);
        exec.shutdownNow();    
    }   
}

You need a synchronized keyword for the run method.

YuanXL
  • 41
  • 2