是否应同步运行方法?为什么或为什么不呢?

我一直认为在实现Runnable的java类中同步run方法是多余的。我试图弄清楚人们为什么这样做:

public class ThreadedClass implements Runnable{
    //other stuff
    public synchronized void run(){
        while(true)
             //do some stuff in a thread
        }
    }
}

这似乎是多余和不必要的,因为他们正在为另一个线程获取对象的锁定。或者更确切地说,他们明确表示只有一个线程可以访问run()方法。但是,既然它是 run 方法,那么它本身不就是它自己的线程吗?因此,只有它可以访问自己,而不需要单独的锁定机制?

我在网上发现了一个建议,通过同步run方法,您可以创建一个事实线程队列,例如通过执行以下操作:

 public void createThreadQueue(){
    ThreadedClass a = new ThreadedClass();
    new Thread(a, "First one").start();
    new Thread(a, "Second one, waiting on the first one").start();
    new Thread(a, "Third one, waiting on the other two...").start();
 }

我个人永远不会这样做,但它引发了一个问题,即为什么有人会同步run方法。任何想法为什么或为什么不应该同步运行方法?


答案 1

同步 的 ) 方法是完全没有意义的,除非您想在多个线程之间共享 ,并且想要按顺序执行这些线程。这在术语上基本上是矛盾的。run(RunnableRunnable

从理论上讲,还有另一种更复杂的方案,您可能希望同步该方法,这再次涉及在多个线程之间共享,但也使用和。在Java的21年多时间里,我从未遇到过它。run()Runnablewait()notify()


答案 2

使用 over 有 1 个优点,那就是生成的字节码将缩短 1 个字节,因为同步将是方法签名的一部分,而不是操作本身。这可能会影响 JIT 编译器内联该方法的机会。除此之外,没有区别。synchronized void blah()void blah() { synchronized(this) {

最好的选择是使用内部以防止有人可能锁定您的显示器。它实现了相同的结果,而没有邪恶的外部锁定的缺点。您确实有额外的字节,但它很少会有所作为。private final Object lock = new Object()

所以我会说不,不要在签名中使用关键字。相反,请使用类似的东西synchronized

public class ThreadedClass implements Runnable{
    private final Object lock = new Object();

    public void run(){
        synchronized(lock) {
            while(true)
                 //do some stuff in a thread
            }
        }
    }
}

编辑以回复评论:

考虑一下同步的作用:它阻止其他线程进入相同的代码块。所以想象你有一个像下面这样的类。假设当前大小为 10。有人试图执行添加,并强制调整后备数组的大小。当他们正在调整数组大小时,有人在不同的线程上调用了 。现在突然之间,你试图访问,它轰炸了你。同步应该防止这种情况发生。在多线程程序中,您只需要同步即可。makeExactSize(5)data[6]

class Stack {
    int[] data = new int[10];
    int pos = 0;

    void add(int inc) {
        if(pos == data.length) {
            int[] tmp = new int[pos*2];
            for(int i = 0; i < pos; i++) tmp[i] = data[i];
            data = tmp;
        }
        data[pos++] = inc;
    }

    int remove() {
        return data[pos--];
    }

    void makeExactSize(int size) {
        int[] tmp = new int[size];
        for(int i = 0; i < size; i++) tmp[i] = data[i];
        data = tmp;
    }
}