更具体地说,我的问题是主线程方法是否已经同步? 例如:
@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不同步。是否需要同步或不需要同步?
答案 0 :(得分:2)
您当前问题的答案是肯定的,您必须同步示例中的getObjectFromMainThread
和setObjectFromMainThread
方法。 为什么这个需要的答案是一个强大的深洞兔子。
多线程的一般问题是当多个线程访问共享,可变状态时会发生什么。在这种情况下,共享的可变状态为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中的细节。