gpt4 book ai didi

java - 何时强制执行对 UI 线程中字段的原子性或 volatile 访问?

转载 作者:行者123 更新时间:2023-11-30 10:27:20 24 4
gpt4 key购买 nike

为了更好地理解并发(作为新手),我需要知道主 (UI) 线程中的内存究竟是如何与工作线程共享的。

例如,对于 AsyncTask,我从来不需要使用 synchronized 或 volatile 等关键字,也不需要使用 AtomicReferences 将主线程中的字段分配为原子。 据我所读,这是因为 AsyncTask 被设计为使用主线程的后台线程池,并且由于其位置,它共享对这些变量的访问(例如调用 publishProgress() 来更新进度条的百分比)。

但是当我使用标准 Thread 实例时,我从该实例内部为主线程中的变量分配了一个新值...如果我从主线程读取该值,它不会更新。那么 Android 是否只对 AsyncTask 等特殊情况强制执行原子性?

例如:

private class ExportAllTask extends AsyncTask<Void, Void, Void>
{
@Override
protected void onPreExecute()
{
super.onPreExecute();

write_complete = false;//this update is visible in the main thread
}

@Override
protected Void doInBackground(Void... voids)
{
//do stuff
}

@Override
protected void onPostExecute(Void aVoid)
{
super.onPostExecute(aVoid);

write_complete = true;
}

@Override
protected void onCancelled()
{
super.onCancelled();

write_complete = true;
}
}

允许来自主线程中订阅者的回调在 AsyncTask 生命周期的任何时刻根据 write_complete 的状态做出响应。

但是如果我使用一个基本的线程(只是出于示例目的而写的):

private void simple_export()
{
new Thread(new Runnable()
{
@Override
public void run()
{
write_complete = false;

for (int i = 0; i < some_int; i++)
{
//do stuff
}

write_complete = true;
}
}.run();
}

write_complete 的“发布”对于主线程中的访问者是不可见的。现在,我可以在 UI 上运行这个线程。 但出于异步目的,在某些时候我还希望线程 hibernate ,或者等待 CountdownLatch 因 UI 中发生更新而释放。现在,如果我在 UI 线程“上”运行它, sleep 将挂起整个 Activity 。这是我不想要的。

真的,我想知道标题中特定于 Android 的问题的答案:

什么时候应该对 UI 线程中的字段强制执行原子性(或可变访问)以共享对工作线程的访问?免责声明:不使用处理程序(这是一种解决方案,但本质上对于一项任务来说是不必要的)。

--

更新:我了解了一点有关并发包在 Android 中的工作原理。我有一个 WRAPPER boolean 变量和一个在 Activity 范围内定义的对象变量。同步块(synchronized block)对于写入多个工作线程访问的对象很有用。例如,AsyncTask 和访问 boolean 值的线程需要 boolean 值在线程内同步,因为它更新了值。 AsyncTask 还更新了 onPreExecute 中的值,但不需要锁定,因为它实例化了 Thread 实例(并具有后台线程池签名)。对象(定义类型)需要具有 volatile 关键字但无法同步(不确定原因)。

编辑:将 boolean 值更正为 boolean 值

最佳答案

Android的内存和线程模型继承自Java。 Android 不会以任何方式改变此模型。

为什么可以在AsyncTaskonPreExecute()onPostExecute() 中操作write_complete 变量的原因是这些方法在 UI 线程上运行。因此,如果您也在 UI 线程中读取 write_complete 的值,则不涉及多线程。

另一方面,如果您要在 doInBackground() 方法(在后台线程上执行)中更改 write_complete 的值,那么您必须使对该变量的线程安全访问。

在这个简单的情况下,单个 boolean 变量被分配了 truefalse 值,您有三个主要选择:

  1. 将变量声明为 volatile 以使任何更改立即对所有线程可见
  2. 使用锁显式同步对变量的访问(这是涉及 synchronize 关键字的锁)
  3. 使用 AtomicBoolean 而不是简单的 boolean 值

一般的答案是:任何被多个线程访问的可变状态都必须显式地成为线程安全的

请注意“可变”条件 - final 状态根据定义是线程安全的。

关于java - 何时强制执行对 UI 线程中字段的原子性或 volatile 访问?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45331217/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com