在同步块内使用wait()

时间:2018-10-16 21:41:39

标签: java android concurrency android-service java-threads

我偶然发现了Android Service类中的一段代码,该代码具有带有等待语句的同步块。 代码如下:

    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(),所以有人可以向我解释以上代码在做什么吗?

2 个答案:

答案 0 :(得分:0)

部分问题涉及多线程,这是一个非常复杂的主题。我建议从tutorial like this one开始获得这些答案。

以上代码将延迟日志输入10秒。但是,IntentService只有1个工作线程,因此如果连续请求的发生频率超过每10秒一次,则将积压连续请求。

因为只涉及1个工作线程,所以使用同步确实是错误的答案。为什么不放弃IntentService,而仅使用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的built-in message queueing system来创建并行执行的外观,而不必担心多线程的复杂性。

答案 1 :(得分:0)

您的陈述“任何数量的线程都可以进入synchronized块”是错误的。

理论上,如果一个线程位于synchronized块中,则这将阻止其他线程进入。对于IntentService,这是不可能的,因为IntentService使用单个工作线程来处理工作量。

调用wait()是线程同步方法,而不是延迟方法。这与调用sleep()不同,后者仅在特定时间段内阻塞线程。当您调用wait()时,它将阻塞线程,直到另一个线程调用notify(),该线程用于协调多个线程之间的活动。 wait(10000)阻塞线程,直到从另一个线程调用notify()为止,或者直到超时到期(在这种情况下为10秒)。因此,看起来应该在某个地方有另一个线程正在调用notify()对象上的IntentService来唤醒它。

使用notify()wait()会带来额外的复杂性。为了调用这些方法中的任何一个,必须首先获得对象监视器的锁定(通过使用synchronized)。这意味着对wait()notify()的调用必须在对象上synchronized的{​​{1}}块内或synchronized方法内。

调用synchronized的线程实际上释放了对象上的锁。这意味着该线程在wait()块/方法内被阻止,但是在等待时该对象没有锁定。一旦synchronized被调用(或超时已过期),线程将重新获得对象上的锁并继续执行。

有关在Java中使用notify()notify()的更多信息,请搜索这些术语并进行阅读。


如果应该做的只是延迟10秒,然后向logcat写入内容,那么该代码将非常复杂。您可以只调用wait()而不是sleep()来调用wait()语句。但是,正如另一位发布者所指出的那样,如果经常调用此synchronized,则会造成积压,因为对Service的每次调用都会延迟10秒,并且由于只有一个工作线程,所有呼叫均已序列化。例如:在10:00:00调用onHandleIntent(),logcat中的条目将在10:00:10出现。如果在10:00:01再次调用startService(),则该条目将在10:00:20之前不会出现在日志中,因为第二个对startService()的调用要到10:00才会发生:10。