Java volatile引用是在线程之间传递MotionEvents的安全方法吗?
我对这种方法的安全性感到好奇,我曾考虑在Android应用程序中使用这种方法来传递触摸事件(并测试我对Java并发性的理解)。以下是基本知识: 我有一个连接到SurfaceHolder.Callback的SurfaceView来获取用户输入事件,主要是Java volatile引用是在线程之间传递MotionEvents的安全方法吗?,java,android,multithreading,Java,Android,Multithreading,我对这种方法的安全性感到好奇,我曾考虑在Android应用程序中使用这种方法来传递触摸事件(并测试我对Java并发性的理解)。以下是基本知识: 我有一个连接到SurfaceHolder.Callback的SurfaceView来获取用户输入事件,主要是onTouchEvent回调。调用onTouchEvent方法后,我会查看event.getAction()==MotionEvent.ACTION\u UP,如果是,则调用我命名的postTouchEvent方法,它是我的应用程序线程的成员方法,
onTouchEvent
回调。调用onTouchEvent
方法后,我会查看event.getAction()==MotionEvent.ACTION\u UP
,如果是,则调用我命名的postTouchEvent
方法,它是我的应用程序线程的成员方法,用于更新应用程序的状态并绘制到画布
表面观察
@Override
public boolean onTouchEvent(final MotionEvent event)
{
mAppThread.postTouchEvent(event);
}
应用线程
private volatile MotionEvent mInputEvent;
public void postTouchEvent(final MotionEvent event)
{
this.mInputEvent = event;
}
@Override
public void run()
{
// while loop ...
if (this.mInputEvent != null)
{
final MotionEvent inputEvent = this.mInputEvent;
this.mInputEvent == null;
// update state based on inputEvent (not this.mInputEvent)
}
// draw to canvas
}
现在我明白了它肯定不是原子的,但既然我在从框架接收到它后将其视为不可变的,这难道不起作用吗?(而不是同步post方法和if语句,我没有问题,但我要求学习。)
这是我的想法。我知道我将有一个对该对象的有效引用,但我不确定在什么状态下我将实际看到该对象。虽然测试一切正常,但我知道线程异常是多么罕见,即使有些东西坏了
此外,我还发现了一个问题:如果出现另一个MotionEvent,则run()
方法中的inputEvent可能会被设置为与this.mInputEvent!=已选中null,但这实际上不是问题
那么,我有什么遗漏吗?或者,就我的目的而言,这应该是正确的吗?我认为这是“安全的”,将您已经确定的关于丢失事件的点模化
volatile上的写入操作和后续读取操作之间存在“发生在”关系。这与单个线程中动作固有的“发生在”关系相结合,意味着您的应用程序线程将看到事件对象在其引用写入volatile时的真实状态
当然,如果事件侦听器线程在更新引用后更改事件对象的状态,则无法保证应用程序线程会看到它们。同上,如果第三个线程更新事件对象。否,这是不安全的,但不是出于您可能期望的原因
。这是将MotionEvents发送到视图层次结构的代码。第1841行是finally
块的一部分,该块调用刚刚调度的MotionEvent
MotionEvents不像大多数对象那样被垃圾收集,它们被池化和回收,以避免事件分派期间不必要的内存分配和垃圾收集。循环使用MotionEvent会将其返回到对象池,以便在以后需要新的MotionEvent时再次使用。调用recycle()
后,应认为MotionEvent无效
您的示例代码可能最终读取一个MotionEvent对象,该对象已被框架重用,现在包含完全不同的数据
如果您计划在onTouchEvent
返回后挂起MotionEvent,请使用克隆。staticget()
方法将从对象池返回具有相同内容的新MotionEvent
处理完动作事件后,应调用recycle()
,然后get()
将其返回到池中。如果您忘记了这一步,这并不是什么大问题,它将成为常规Java垃圾,框架将在需要时创建新的MotionEvents。但是,系统可以非常快速地调度MotionEvents,在这种情况下,配合此优化可以对某些设备的性能产生重大影响。这正是我想要了解的。感谢您抽出时间提供如此详细的答案和建议的解决方案。