我偶然发现了一段Android服务类中的一段代码,该代码具有带有等待语句的同步块。 代码如下:
public class MyService extends IntentService{
protected void onHandleIntent(Intent intent){
synchronized(this){
try{
wait(10000);
}catch(InterruptedException e){
e.printStackTrack();
}
String message = intent.getStringExtra("Message");
showMessage(message);
}
}
}
上面的代码是否意味着任意数量的线程都可以进入synchronized
块?我知道sleep
Thread
置于"已阻止"状态。这和Thread
呼叫wait()
一样吗? 基本上当我将文本传递给Service
时,我希望Service
等待 10 秒,然后在LogCat
中显示消息。 我从来没有使用过wait()
所以任何人都可以向我解释上面的代码在做什么吗?
你的陈述"任意数量的线程都可以进入synchronized
块"是错误的。
从理论上讲,如果一个线程在synchronized
块内,这会阻止其他线程进入。这在IntentService
的情况下是不可能的,因为IntentService
使用单个工作线程来处理工作负载。
调用wait()
是一种线程同步方法,而不是延迟方法。这与调用sleep()
不同,后者只是在特定时间内阻塞线程。 当你调用wait()
时,这会阻塞线程,直到另一个线程调用notify()
,用于协调多个线程之间的活动。wait(10000)
阻塞线程,直到从另一个线程调用任一notify()
或直到超时到期(在本例中为 10 秒(。所以这看起来应该在某处有另一个线程在IntentService
对象上调用notify()
来唤醒它。
这里还有一个与使用notify()
和wait()
相关的额外复杂性。为了调用这些方法中的任何一个,必须首先在对象的监视器上获取锁(通过使用synchronized
(。这意味着对wait()
和notify()
的调用必须在synchronized
块内或在对象上synchronized
synchronized
方法内。
调用wait()
线程实际上释放对象上的锁。这意味着线程在synchronized
块/方法中被阻塞,但在等待时它没有对对象的锁定。调用notify()
(或超时已过期(后,线程将重新获得对象的锁并继续执行。
有关在 Java 中使用notify()
和wait()
的更多信息,请搜索这些术语并阅读相关内容。
做的只是延迟 10 秒,然后向 logcat 编写一些东西,那么这段代码就非常复杂了。您可以只调用sleep()
而不是不需要synchronized
语句的wait()
。但是,正如另一张海报所指出的那样,如果经常调用此Service
,这将创建积压工作,因为对onHandleIntent()
的每个调用都将延迟 10 秒,并且由于只有 1 个工作线程,因此所有调用都是序列化的。示例:在 10:00:00 调用startService()
,logcat 中的条目将显示在 10:00:10。如果在 10:00:01 对startService()
进行了另一次调用,则该条目直到 10:00:20 才会出现在 logcat 中,因为对onHandleIntent()
的第二次调用要到 10:00:10 才会发生。
你的问题的一部分涉及多线程,这是一个相当复杂的话题。我建议从这样的教程开始,以获得这些答案。
上面的代码将用于将日志条目延迟 10 秒。但是,IntentService
只有 1 个工作线程,因此如果连续请求每 10 秒发生一次以上,则它们将被积压。
由于仅涉及 1 个工作线程,因此使用同步确实是错误的答案。为什么不放弃意图服务,而只是使用CountDownTimer
在UI线程上完成所有这些操作?
final String msg = intent.getStringExtra("Message");
new CountDownTimer(10000, 10000) {
@Override
public void onTick(long millisUntilFinished) {}
@Override
public void onFinish() {
showMessage(msg);
}
}.start();
这样,您就可以利用 Android 的内置消息队列系统来创建并行执行的外观,而无需多线程的复杂性。