换句话说,根据我的理解,这不是线程安全的(对于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()
)?
使用IntentService会对这两个示例(代码位于onHandleIntent()
中)产生影响吗?
答案 0 :(得分:1)
它与Java或Android中其他任何地方的同步需求相同 - 如果您有多个线程访问变量,您可能需要同步方法来防止线程干扰,或者您可能需要将变量声明为volatile,以便每个线程获得最新的副本。
Android特别需要注意的是,onStartCommand
将由主线程上的系统调用,因此除非您另外执行,否则您将阻止主UI线程。如果使用IntentService
,则在另一个线程上调用onHandleIntent
方法,因此您可以在那里卸载长时间运行的任务,而无需担心创建和使用单独线程的机制。
您可以使用易变实例变量的地方是在onHandleIntent
中改变变量,然后在onDestroy
中访问它。在这里,您希望确保在调用onDestroy
时获得一份新的副本。
你的例子可以说的是,在你的第一个例子中,Log语句中a的值是未定义的,而在第二个例子中,如果这是一个新对象,则它是1。
编辑:最重要的是,如果你多次调用startService(),你真的不应该指望实例变量的值是什么(我们不知道它是否会成为同一个实例它可能已经被破坏了)你不应该依赖于对startService()的调用顺序必须与它们执行的顺序相同(即使这似乎是它的实现方式)。
将请求填入数组并将它们作为一个调用发送到startService(),或者如果需要这样的保证,则使用服务中的局部变量。
如果你在服务中使用多线程这是一个更复杂的场景,你应该发布一个问题的具体例子,因为不知道你在尝试什么,就不可能给出建议。