Java 即使变量已更新,whlie循环也不会退出

Java 即使变量已更新,whlie循环也不会退出,java,variables,android-asynctask,global,Java,Variables,Android Asynctask,Global,我创建了一个嵌套类,它扩展了AsyncTask以从数据库提取数据。 提取完成后,它会将全局变量(“NotificationsTracted”)设置为true,表示该过程已完成 在主调用代码中,我设置了一个while循环,在使用提取的数据之前,它会等待全局变量变为true,即 while(!notificationsExtracted) {} ...now continue running other code... 在除一部以外的所有手机上,这一功能都能正常工作,但一部手机(Conexis x

我创建了一个嵌套类,它扩展了AsyncTask以从数据库提取数据。 提取完成后,它会将全局变量(“NotificationsTracted”)设置为true,表示该过程已完成

在主调用代码中,我设置了一个while循环,在使用提取的数据之前,它会等待全局变量变为true,即

while(!notificationsExtracted) {}
...now continue running other code...
在除一部以外的所有手机上,这一功能都能正常工作,但一部手机(Conexis x2-Android 7.0)拒绝反映设置为true的全局变量

当我做日志记录时,它显示了实例化类的代码流,拉取数据,将全局变量设置为true,然后什么都没有。 在其他手机上,它执行上述操作,但随后继续在主程序中运行进一步的代码

简单地说,我在调用程序中有以下内容

public class FragmentMain extends Fragment {
  static private Boolean notificationsExtracted;
...
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
      View view = inflater.inflate(R.layout.fragment_main_layout, parent, false);
    ...
    Log.i("notif", "1");
    notificationsExtracted = false;
    GetNotificationsNewMySQL getNotificationsNewMySQL = new GetNotificationsNewMySQL();
    getNotificationsNewMySQL.execute("");
    while (!notificationsExtracted) { };
    Log.i("notif", "2");
    ...
然后是嵌套类

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

        @Override
        protected String doInBackground(String... params) {
            try {
                Class.forName("com.mysql.jdbc.Driver");
                Connection con = DriverManager.getConnection(url, user, pass);

                Statement st = con.createStatement();
                String q = "SELECT COUNT(*) AS cnt FROM training.app_notifications";
                Log.i("notif", "a");
                ResultSet rs = st.executeQuery(q);
                Log.i("notif", "b");
                ResultSetMetaData rsmd = rs.getMetaData();
                Log.i("notif", "c");
                while (rs.next()) {
                    notificationCount = Integer.parseInt(rs.getString(1).toString());
                }
                Log.i("notif", "d");
                notificationsExtracted = true;
            } catch (Exception e) {
                Log.i("notif", "error extracting");
                e.printStackTrace();
            }
            if (notificationsExtracted)
                Log.i("notif", "true");
            else
                Log.i("notif", "false");
            return "";
        }

        @Override
        protected void onPostExecute(String result) {
        }
    }
除了一部手机,我得到了以下结果,手机挂起,即它永远不会通过while循环:


2019-11-15 11:20:57.153 20089-20089/com.example.pdcapp I/Notif: 1
2019-11-15 11:20:57.154 20089-20089/com.example.pdcapp I/Notif: 2
2019-11-15 11:20:57.196 20089-20089/com.example.pdcapp I/notif: 1
2019-11-15 11:20:57.267 20089-20348/com.example.pdcapp I/notif: a
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: b
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: c
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: d
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: true

我将非常感谢您的帮助。作为参考,我之前在以下链接上寻求帮助

能否请您在获取字符串q、结果集和结果集元数据的行后添加记录器?可能是在这些行上出现了阻塞。

能否在获取字符串q、结果集和结果集元数据的行之后添加记录器?可能是在这些方面遇到了问题。

您所做的违背了异步执行的原则。如果您启动一个异步任务,但等到它被找到时,它就不是真正的异步。
不过这也没关系,有时候你只需要按照一定的顺序完成一些事情,但你不能在主线程上完成

我不太清楚为什么你的程序在技术层面上不起作用,但我想我曾经遇到过类似的问题。我相信在Java中,从一个线程内更新变量并不一定也会更新所有其他线程的变量。Android Studio是否会在while循环中向您发出警告?
我希望有更多Java多线程经验的人能谈谈这一点

但是,问题的解决方法很简单:

您希望while循环后的任何代码都在AsyncTask完成执行后执行,因此只需在onpostExecute方法中执行该代码即可。

您所做的操作违反了异步执行的原则。如果您启动一个异步任务,但等到它被找到时,它就不是真正的异步。
不过这也没关系,有时候你只需要按照一定的顺序完成一些事情,但你不能在主线程上完成

我不太清楚为什么你的程序在技术层面上不起作用,但我想我曾经遇到过类似的问题。我相信在Java中,从一个线程内更新变量并不一定也会更新所有其他线程的变量。Android Studio是否会在while循环中向您发出警告?
我希望有更多Java多线程经验的人能谈谈这一点

但是,问题的解决方法很简单:

您希望在异步任务完成执行后执行while循环后的任何代码,因此只需在onpostexcute方法中执行该代码即可。

异步任务的全部要点是在不同线程中执行阻塞长任务,以避免阻塞UI线程和冻结应用程序。让一个while循环什么也不做,除了吃掉所有的CPU和冻结UI线程直到“后台”任务完成,这比不使用异步任务更糟糕(而且你也在以非线程安全的方式进行)。请阅读如何正确使用异步任务,因为您执行异步任务的方式是一条死胡同。异步任务之所以使用异步任务,是因为它不是易失性的、原子性的或从snchronized块访问的。因此,可见性不能保证一个线程完成的写操作可以被另一个线程看到。但是,如果它是一个静态全局变量,为什么线程不能更新它呢?线程可以。但是Java内存模型并不保证另一个线程会看到更改,除非使用了适当的同步(volatile、atomic、synchronized)。多线程是一个复杂的问题。异步任务的要点是在不同的线程中执行阻塞、长任务,以避免阻塞UI线程和冻结应用程序。让一个while循环什么也不做,除了吃掉所有的CPU和冻结UI线程直到“后台”任务完成,这比不使用异步任务更糟糕(而且你也在以非线程安全的方式进行)。请阅读如何正确使用异步任务,因为您执行异步任务的方式是一条死胡同。异步任务之所以使用异步任务,是因为它不是易失性的、原子性的或从snchronized块访问的。因此,可见性不能保证一个线程完成的写操作可以被另一个线程看到。但是,如果它是一个静态全局变量,为什么线程不能更新它呢?线程可以。但是Java内存模型并不保证另一个线程会看到更改,除非使用了适当的同步(volatile、atomic、synchronized)。多线程是一个复杂的问题。在Java中,在线程范围之外定义的变量总是在所有线程中更新。如果这是一个问题,它可能不会在其他手机上工作。不过,
onPostExecute
可能是一个可行的解决方案。我也尝试了onPostExecute,让它将变量设置为true,而不是在asyncTask中,但随后应用程序挂起在所有手机上。我了解线程需要并行运行,而不是让它占用我的主线程,问题是,我想让它与主代码分开,而且操作速度非常快(相对而言),所以我不介意等待那一秒,等待它完成。我没有看到你对解决方案的建议,我会看看我是否能做到,谢谢。我所做的就是你

2019-11-15 11:20:57.153 20089-20089/com.example.pdcapp I/Notif: 1
2019-11-15 11:20:57.154 20089-20089/com.example.pdcapp I/Notif: 2
2019-11-15 11:20:57.196 20089-20089/com.example.pdcapp I/notif: 1
2019-11-15 11:20:57.267 20089-20348/com.example.pdcapp I/notif: a
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: b
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: c
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: d
2019-11-15 11:20:57.274 20089-20348/com.example.pdcapp I/notif: true