我是否必须在主线程方法上使用synchronized?

时间:2017-08-26 09:56:27

标签: java multithreading

更具体地说,我的问题是主线程方法是否已经同步? 例如:

    @MainThread
    class MyClass{
        private Object o = null;

        @MainThread
        MyClass(){
        }

        @MainThread
        public Object getObjectFromMainThread(){
            return this.o.getObj2();
        }

        @MainThread
        public void setObjectFromMainThread(Object obj){
            obj.set(1);
            this.o=obj;
        }

        @AnyThread
        public synchronized Object getObjectFromAnyThread(){
            return this.o;
        }

        @AnyThread
        public synchronized void setObjectFromAnyThread(Object obj){
            this.o=obj;
        }
    }

仅从主线程调用的方法getObjectFromMainThread和setObjectFromMainThread不同步。是否需要同步或不需要同步?

1 个答案:

答案 0 :(得分:2)

您当前问题的答案是肯定的,您必须同步示例中的getObjectFromMainThreadsetObjectFromMainThread方法。 为什么这个需要的答案是一个强大的深洞兔子。

多线程的一般问题是当多个线程访问共享,可变状态时会发生什么。在这种情况下,共享的可变状态为this.o。所涉及的任何线程是否都是主线程并不重要,它是在多个线程正在运行时出现的一般问题。

我们正在处理的问题归结为"线程在一个或多个线程正在写入状态的同时读取状态时会发生什么?"及其所有变化。这个问题引发了一些非常复杂的子问题,比如每个处理器核心在自己的处理器缓存中都有自己的对象副本。

处理此问题的唯一方法是明确将要发生的事情。 synchronized机制就是这样一种方式。同步涉及 lock ,当您使用synchronized方法时,锁定为this

public synchronized void foo() {
    // this code uses the same lock...
}

public void bar() {
    synchronized (this) {
        // ...as this code
    }
}

在同一个锁上同步的所有程序代码中,只有一个线程可以同时执行它。这意味着,如果(且仅当)与this.o交互的所有代码都与this锁同步运行,则可以避免前面描述的问题。

在您的示例中,setObjectFromAnyThread()的存在意味着您还必须同步setObjectFromMainThread(),否则有时会同步访问this.o中的状态 - 有时 - 不同步,这是一个破坏程序。

同步是有代价的:因为你的锁定位代码一次由一个线程运行(而其他线程要等待),你可以删除使用多线程获得的部分或全部加速首先是线程化。在某些情况下,您最好忘记存在多线程并使用更简单的单线程程序。

在多线程程序中,将共享的可变状态的数量限制到最小是有用的。任何一次被多个线程访问的状态都不需要同步,并且更容易推理。

@MainThread注释at least as it exists in Android表示该方法仅用于在主线程上访问。 它没有做任何事情,它只是作为程序员和编译器的信号。运行时不涉及技术保护机制;这一切都归结为你的自律和一些编译时工具支持。这种缺乏保护的优点是没有运行时开销。

多线程编程很复杂,容易出错。要做到正确的唯一方法就是真正理解它。有一本名为Java Concurrency In Practice的书,它非常好地解释了并发的一般原则和问题以及Java中的细节。