【问题标题】:Commit clear interrupted state提交清除中断状态
【发布时间】:2012-06-30 03:54:13
【问题描述】:

在我正在开发的应用程序中,我有一个正在循环运行的线程。在循环内部,会评估几个条件,并根据这些条件,将一个值或另一个值存储在 SharedPreferences 中。

public void run()
{
  try
  {
    SharedPreferences preferences = 
       context.getSharedPreferences("MyPrefs", Activity.MODE_PRIVATE);

    SharedPreferences.Editor editor = preferences.edit();

    while (true)
    {                       
      if (condition1)
      {
        editor.putBoolean("mykey", "1");
      }
      else if (condition 2)
      {
        editor.putBoolean("mykey", "2");            
      }
      editor.commit();

      if (isInterrupted())
         throw new InterruptedException();              

      Thread.sleep(60000); // 60 seconds
    }
  }
  catch (InterruptedException e)
  {
    Thread.currentThread().interrupt();
  }
}

该线程由onResume方法中的Activity启动,在onPause方法中被中断。

如果线程在休眠时被activity(主线程)打断,则抛出InterruptedException。没关系。

但我的问题是,如果活动(主线程)在运行(而不是睡眠)时中断线程。 “中断标志”设置为true,但是在编辑器上调用commit后,该标志设置为false,所以我无法中断抛出InterruptedException的线程。

我能做什么?

谢谢

【问题讨论】:

    标签: android multithreading sharedpreferences interrupt


    【解决方案1】:

    首先,不要这样做:while (true)

    其次,如果线程被中断:

    if (isInterrupted())
             throw new InterruptedException();              
    
          Thread.sleep(60000); // 60 seconds
        }
      }
      catch (InterruptedException e)
      {
        Thread.currentThread().interrupt();
      }
    

    它捕获中断,然后再次中断线程。这尖叫递归,你的无限while循环没有帮助。

    【讨论】:

    • 我不明白你为什么说我不应该做“while (true)”。在 InterruptedException catch 块中我再次中断线程是因为我必须这样做。请阅读下一篇文章的“不要吞下中断”部分ibm.com/developerworks/java/library/j-jtp05236/index.html
    • 包含任何无限循环都是非常糟糕的编程习惯。这个循环永远不会真正结束,并且会消耗电池和处理能力。
    • 感谢您的回答。我知道无限循环不是一个好习惯,但是在我写的无限循环中,我调用了一个 sleep 方法,所以大部分时间线程都在休眠。另一方面,线程并不总是在运行,它会被其他线程中断。
    • 反正我不明白的是为什么commit方法会清除线程的“中断标志”。
    • 您是否尝试在处理编辑器对象之前检查中断?
    【解决方案2】:

    调用editor.commit() 将执行I/O。如果线程上有挂起的中断,那么这可能会中止 I/O 并清除挂起的中断。

    为了做你想做的事,你可能需要防止线程在提交时被中断。您需要同步访问,以便应用程序只能在线程休眠时中断它。像这样的:

    // This method will interrupt the thread that is looping ONLY while it is sleeping
    public synchronized void interruptNow() {
        threadThatIsLooping.interrupt();
    }
    
    public void run() {
    try {
        SharedPreferences preferences = 
           context.getSharedPreferences("MyPrefs", Activity.MODE_PRIVATE);
        SharedPreferences.Editor editor = preferences.edit();
        while (true) {
            synchronized {
                // Cannot be interrupted within this block                  
                if (condition1) {
                    editor.putBoolean("mykey", "1");
                } else if (condition 2) {
                    editor.putBoolean("mykey", "2");            
                }
                editor.commit();
            }             
            Thread.sleep(60000); // 60 seconds
        }
    } catch (InterruptedException e) {
        // Do whatever you want here when the thread is interrupted while sleeping
    }
    }
    

    【讨论】:

    • 非常感谢您的回答。我会照你说的做。我不明白的是为什么“editor.commit”不抛出 InterruptedException 而不是清除挂起的中断。
    【解决方案3】:

    我刚刚遇到了同样的问题并找到了解决方案。

    您可以使用editor.apply() 而不是editor.commit()

    apply() 代替 commit() 起作用的原因是它在一个新线程上进行 I/O,因为它不需要等待返回值:

    与 commit() 不同,commit() 将其偏好写入持久化 同步存储,apply() 将其更改提交到内存中 SharedPreferences 立即但开始异步提交 磁盘,您将不会收到任何故障通知。如果另一个编辑 此 SharedPreferences 执行常规 commit() 而 apply() 是 仍然未完成,commit() 将阻塞,直到所有异步提交都完成 完成以及提交本身。

    【讨论】:

    • 感谢您的回答。
    猜你喜欢
    • 2020-11-11
    • 2022-11-01
    • 2021-03-08
    • 1970-01-01
    • 2018-04-11
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 2013-07-22
    相关资源
    最近更新 更多