换句话说,据我所知,这不是线程安全的(对于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线程。如果您使用IntentService
,onHandleIntent
方法会在另一个线程上调用,因此您可以在那里卸载长期运行的任务,而不用担心创建和使用单独线程的机制。
可以使用volatile实例变量的地方是,如果在onHandleIntent
中对变量进行突变,然后在onDestroy
中访问它。在这里,您需要确保在调用onDestroy
时有一个新的副本。
关于您的示例,可以说的是,在第一个示例中,Log语句中的a值是未定义的,在第二个示例中如果这是一个新对象,则为1。
编辑:底线是,如果您多次调用startService(),您真的不应该指望实例变量的值是任何值(我们不知道它是否会是同一个实例,因为它可能已经被销毁),并且您不应该指望对startService((尽管这似乎是它的实现方式)。
将请求填充到一个数组中,并将它们作为对startService()的一个调用发送,或者如果需要这样的保证,可以在Service中使用局部变量。
如果您在服务中遇到了多线程的更复杂场景,您应该发布一个问题的具体示例,因为如果不知道您在尝试什么,就不可能给出建议。