【问题标题】:Synchronized run() method同步的 run() 方法
【发布时间】:2013-11-10 09:43:24
【问题描述】:

众所周知,只能同时运行一种同步方法。所以我的问题是,如果我将 run() 方法声明为同步,然后运行多线程,其他线程是否可以运行 run() 方法? 像这样:

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

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

thread2是否可以运行或者thread2会等待thread1退出run()方法?

【问题讨论】:

    标签: java multithreading synchronized


    【解决方案1】:

    实例方法上的synchronized 关键字可防止该方法的并发调用在同一实例上调用时

    试试下面的(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);
            }
        }
    }
    

    这将输出如下内容:

    1000
    1001
    1001
    

    换句话说,每个任务自创建以来经过的时间约为 1 秒,因此这意味着它们可以同时运行。

    现在试试下面的(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);
            }
        }
    }
    

    将同一个实例传递给所有 3 个线程意味着线程将尝试在同一个实例上调用 run。这会输出如下内容:

    1001
    2001
    3001
    

    换句话说,每个任务都等待前一个任务。

    如果你真的想要synchronize all of run为每个对象,你可以指定你自己的监控对象(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);
                }
            }
        }
    }
    

    即使我们每次都创建一个新任务,它的输出也与示例 2 相同。

    另请参阅:Should you synchronize the run method? Why or why not?

    【讨论】:

    • 代码实现不使用同一个可运行实例,而是使用新的 SynchRun 实例。我运行了它但没有看到相同的结果,但是当通过相同的 runnable 实例时确实看到了差异。
    【解决方案2】:

    您创建了两个 Test 实例,并且每个线程运行两个线程,因此其他线程不可能运行 run() 方法。 仅当您的两个线程使用相同的实例运行时:

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

    run 方法需要一个 synchronized 关键字。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-02
      • 1970-01-01
      • 2017-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-18
      相关资源
      最近更新 更多