访问android服务的实例变量时,我什么时候需要同步



换句话说,据我所知,这不是线程安全的(对于startService()的多次调用):

public class RaceService extends Service {
volatile int a; // edit: added volatile to clarify my point
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread(new Runnable() {
@Override
public void run() {
a++;
Log.w("RaceService", "a: " + a);
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}

因为只创建了一个服务实例(尽管从未找到明确的断言——如果有人能告诉我服务实际实例化的来源(通过反射?),我会很感激)。如果每个startService()创建一个实例,那么每次调用startService时只会打印1。

但这是吗

public class RaceService2 extends Service {
int a;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
a++;
Log.w("RaceService2", "a: " + a);
return super.onStartCommand(intent, flags, startId);
}
}

线程安全(用于startService()的多次调用)?

在这两个示例中(代码位于onHandleIntent()中),使用IntentService会有什么不同吗?

这与Java或Android中其他任何地方的同步需求相同-如果您有多个线程访问变量,您可能需要同步方法来防止线程干扰,或者您可能需要将变量声明为volatile,以便每个线程都能获得最新的副本。

安卓系统唯一需要注意的是,onStartCommand将由系统在主线程上调用,因此除非另行设置,否则您将阻塞主UI线程。如果您使用IntentServiceonHandleIntent方法会在另一个线程上调用,因此您可以在那里卸载长期运行的任务,而不用担心创建和使用单独线程的机制。

可以使用volatile实例变量的地方是,如果在onHandleIntent中对变量进行突变,然后在onDestroy中访问它。在这里,您需要确保在调用onDestroy时有一个新的副本。

关于您的示例,可以说的是,在第一个示例中,Log语句中的a值是未定义的,在第二个示例中如果这是一个新对象,则为1。

编辑:底线是,如果您多次调用startService(),您真的不应该指望实例变量的值是任何值(我们不知道它是否会是同一个实例,因为它可能已经被销毁),并且您不应该指望对startService((尽管这似乎是它的实现方式)。

将请求填充到一个数组中,并将它们作为对startService()的一个调用发送,或者如果需要这样的保证,可以在Service中使用局部变量。

如果您在服务中遇到了多线程的更复杂场景,您应该发布一个问题的具体示例,因为如果不知道您在尝试什么,就不可能给出建议。

最新更新