Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/214.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 简单线程崩溃Android应用程序_Java_Android_Multithreading - Fatal编程技术网

Java 简单线程崩溃Android应用程序

Java 简单线程崩溃Android应用程序,java,android,multithreading,Java,Android,Multithreading,在Android应用程序中创建一个启动线程时,我发现了一个非常奇怪的问题 如果我有以下类线程: 并将其添加到活动的onCreate(…)方法中的某个位置,如: 应用程序将崩溃 但是如果我将run()方法更改为: 它停止撞击 即使我通过使用锁、notify()和wait()解决了问题,问题仍然存在: 为什么使用直接访问字段时,应用程序会继续工作,而使用该方法时会崩溃?首先,由于您没有提供MCVE,其他人无法重现您的问题。这是不幸的,因为这意味着我们无法确定问题的真正原因是什么。我们只能提出假

在Android应用程序中创建一个启动线程时,我发现了一个非常奇怪的问题

如果我有以下类线程:

并将其添加到活动的onCreate(…)方法中的某个位置,如:

应用程序将崩溃

但是如果我将run()方法更改为:

它停止撞击

即使我通过使用锁、notify()和wait()解决了问题,问题仍然存在:


为什么使用直接访问字段时,应用程序会继续工作,而使用该方法时会崩溃?

首先,由于您没有提供MCVE,其他人无法重现您的问题。这是不幸的,因为这意味着我们无法确定问题的真正原因是什么。我们只能提出假设

有些人假设你的问题是由其他原因造成的;e、 g.GUI线程上的无限循环。这是有道理的,但没有明确的证据证明这一点。(我们看不到代码……)

我的假设是这是一个“记忆可见性”问题。Java语言规范有一章定义了一个线程保证看到另一个线程写入内存的值的情况。这些规则相当复杂且技术性很强,但本质上是需要分析一个线程写入的内存与另一个线程读取的后续内存之间是否存在先发生后发生的关系。有很多东西可以让你建立这种关系:

  • 线程写入/读取共享的易失性变量
  • 正在使用相同锁进行同步的线程
  • 发条
  • 螺纹接头
  • 构造函数的完成(对于
    最终
    变量)
但是,对于
running
变量,您的程序中不存在这些内容。这意味着不能保证在
running
变量上循环的线程将看到另一个线程发出的
setRunning
调用的结果:

  • 它可能会立即看到更改
  • 以后可能会看到这些变化
  • 它可能永远也见不到他们
这三种行为都是可能的。。。。在没有一个发生在关系之前

那么,为什么一个版本的代码与另一个版本的代码行为不同呢

我们不能确定。事实上,需要有人对您的示例的本机(机器)代码进行深入分析。这可能与优化器在一种情况下而不是在另一种情况下进行的(合法)重新排序有关。这可能是一个微妙的时间效应

但不管怎样,JLS说编译器没有义务确保写入是可见的。为什么?因为这段代码打破了内存模型的规则

解决方案:

在这种情况下,最简单的解决方案是将
running
声明为
volatile

另一种解决方案是将
isRunning()
setRunning
声明为
synchronized
方法


其中任何一个都足以提供“先发生后发生”的关系。。。并确保
isRunning()
看到了
setRunning()

所做的更新,您是否正在使用
布尔运行和非
布尔运行
?您可以发布stacktrace吗?您是否尝试过初始化该值,以便
getRunning()
肯定会返回一些内容,而不是未初始化的变量?还有,这里要问的问题是什么,你似乎已经修复了你的崩溃?哪一个是您的错误?没有任何stacktrace?我认为问题不是您的TroubleThread,而是UI线程,它可能正在等待一些需要大量时间的事情。我已经用直接访问布尔值和通过get方法测试了您的解决方案,效果很好。因此,我认为这应该取决于您在UI线程中尝试做什么。但是,您可能只需要同步对共享变量的访问。
public class TroubleThread extends Thread{
    boolean running;

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }

    @Override
    public void run() {
        while (isRunning()){
        }//end while
    }//end run
}
public class MyActivity extends Activity {
    TroubleThread  myThread;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        //....
        myThread = new TroubleThread();
        myThread.setRunning(true);
        myThread.start();
    }
}
@Override
    public void run() {
        while (running){ //NOTE THE USE OF DIRECT FIELD ACCESS INSTEAD OF METHOD
        }//end while
    }//end run