Java 何时强制执行对UI线程中字段的原子性或易失性访问?
为了更好地理解并发性(作为新手),我需要知道主(UI)线程中的内存是如何与工作线程共享的 例如,对于AsyncTask,我从来不需要使用synchronized或volatile之类的关键字,也不需要使用原子引用将主线程中的字段指定为原子字段。据我所知,这是因为AsyncTask被设计为使用主线程的后台线程池,并且由于其位置,它可以共享对这些变量的访问(例如调用publishProgress()来更新进度条的百分比) 但是当我使用一个标准线程实例时,我会从该实例内部为主线程中的一个变量指定一个新值。。。如果我从主线程读取该值,它不会被更新。那么Android是否只对AsyncTask这样的特殊情况强制执行原子性呢 例如:Java 何时强制执行对UI线程中字段的原子性或易失性访问?,java,android,concurrency,Java,Android,Concurrency,为了更好地理解并发性(作为新手),我需要知道主(UI)线程中的内存是如何与工作线程共享的 例如,对于AsyncTask,我从来不需要使用synchronized或volatile之类的关键字,也不需要使用原子引用将主线程中的字段指定为原子字段。据我所知,这是因为AsyncTask被设计为使用主线程的后台线程池,并且由于其位置,它可以共享对这些变量的访问(例如调用publishProgress()来更新进度条的百分比) 但是当我使用一个标准线程实例时,我会从该实例内部为主线程中的一个变量指定一个新
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;
}
}
私有类ExportAllTask扩展了AsyncTask
{
@凌驾
受保护的void onPreExecute()
{
super.onPreExecute();
write_complete=false;//此更新在主线程中可见
}
@凌驾
受保护的空位背景(空位…空位)
{
//做事
}
@凌驾
受保护的void onPostExecute(void避免)
{
super.onPostExecute(避免);
write_complete=true;
}
@凌驾
受保护的void onCancelled()
{
super.onCancelled();
write_complete=true;
}
}
允许来自主线程中订阅者的回调根据异步任务生命周期中任何一点的write_complete状态进行响应
但是,如果我使用了一个基本线程(只是出于示例目的编写此线程):
private void simple_export()
{
新线程(newrunnable())
{
@凌驾
公开募捐
{
write_complete=false;
for(int i=0;i
write_complete的“发布”对主线程中的访问器不可见。现在,我可以在UI上运行此线程。但出于异步目的,在某些点上,我还希望线程睡眠,或者由于UI中发生更新而等待CountdownLatch释放。现在,如果我运行此“打开”UI线程,睡眠将挂起整个活动。这是我不想要的
所以说真的,我想知道标题中关于Android的问题的答案:
什么时候应该对UI线程中的字段强制原子性(或易失性访问)以共享对工作线程的访问?免责声明:不使用处理程序(这是一种解决方案,但对于基本上1个任务来说是不必要的)
--
更新:我了解了一点并发程序包在Android中的工作原理。我在活动范围中定义了一个包装布尔变量和一个对象变量。同步块对于写入多个工作线程访问的对象非常有用。例如,一个异步任务和一个访问布尔函数的线程需要d要在线程内同步的布尔值,因为它更新了值。AsyncTask还更新了onPreExecute中的值,但不需要锁定,因为它实例化了线程实例(并且具有后台线程池签名)。对象(定义的类型)需要具有volatile关键字,但无法同步(不确定原因)
编辑:将布尔值更正为布尔值Android的内存和线程模型继承自Java。Android不会以任何方式更改此模型 您可以在
AsyncTask
的onPreExecute()
和onPostExecute()
中操作write\u complete
变量的原因是这些方法在UI线程上运行。因此,如果您还在UI线程中读取write\u complete
的值,则不涉及多线程
另一方面,如果要在doInBackground()
方法中更改write_complete
的值(在后台线程上执行),则必须确保对该变量的访问是安全的
在一个布尔变量被赋值为true
或false
值的简单情况下,您有三个主要选择:
Synchronize
关键字的锁)AtomicBoolean
而不是简单的boolean注意“可变”条件-
final
状态根据定义是线程安全的。谢谢,我不知道doInBackground()实际上,将作用域更改为UI线程之外。此外,当无法强制执行异步线程队列时,是否应使用synchronize代替volatile?如中所示,如果您可以保证每次访问变量的线程不超过1个,则可以使用volatile?据我所知,synchronize将阻止将来的访问释放变量之前,变量的or值。@DavidMaki,volatile
即使多个线程同时访问变量也足够了,只要它是一个简单变量,它的变异是原子的,每个线程要么读取变量,要么写入变量(但不是同时读取和写入)。在SO answer的范围内,我真的不能再深入了。我强烈建议您找到一本关于java多线程的好教程,因为这是一个广泛而复杂的主题。我可以推荐Jacob Jenkov的这一系列教程:
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();
}