一段时间后,while循环会停止执行吗?

时间:2018-07-28 18:05:05

标签: java multithreading while-loop infinite-loop println

由于我对Java还是很陌生,因此我目前正在尝试多线程。现在,我有多个线程都影响同一个long变量。但是,似乎一段时间后除了检查if语句外,什么都不做,而while循环只是停止执行(例如,它无限循环)。如果我只是在while循环中打印某些内容,它确实可以工作。

不起作用:

while(true){
  if(longVariable < 2)
    break;
}

以某种方式起作用:

while(true){
  System.out.println("hi");
  if(longVariable < 2)
    break;
}

这是为什么?

2 个答案:

答案 0 :(得分:2)

while(true){
  if(longVariable < 2)
    break;
}

在此代码中,JVM没有理由相信longVariable会发生变化。它可以有效地将其重写为:

long cached = longVariable;
while(true){
  if(cached < 2)
    break;
}

longVariable执行时,如果cached至少为2,则无限循环,因为System.out.println不会改变。

您必须向编译器提示不允许进行此重写。它可以与JVM上的longVariable一起使用,因为它恰好是通过同步实现的(这是常见的,但不是必需的)。这会插入内存屏障,这意味着volatile long longVariable 的缓存值无效,必须重新读取。

但是不能保证它能正常工作。为了使其正常工作,请声明变量volatile:

AtomicLong

这可以防止其值被缓存。

或者使用类似long之类的东西代替普通的long v; synchronized (something) { v = longVariable; } if (v < 2) ... 变量。

或者,最麻烦的是,使用显式同步(确保对变量的所有读取和写入都在同一“事物”上同步):

import React, { Component } from 'react';
import { Text, View, TextInput, StyleSheet } from 'react-native';
import { Constants } from 'expo';
import { Tile } from 'react-native-elements';

export default class Tel extends Component {

  render() {
    return (
      <View style={styles.tileStyle}>
              <View style={{width: 20, height: 20,}}>
              <Tile

                featured
                caption="Text"
              />
              </View>
              <View style={{width: 20, height: 20,}}>
              <Tile

                featured
                caption="Some Caption Text"
              />
              </View>
              <View style={{width: 20, height: 20,}}>
              <Tile

                featured
                caption="Some"
              />
              </View>

              <View style={{width: 20, height: 20,}}>
              <Tile

                featured
                caption="Text"
              />
              </View>
              <View style={{width: 20, height: 20,}}>
              <Tile

                featured
                caption="Some Caption Text"
              />
              </View>
              <View style={{width: 20, height: 20,}}>
              <Tile

                featured
                caption="Some"
              />
              </View>
            </View>
    );
  }
}

const styles = StyleSheet.create({
  tileStyle: {
    flex: 1,
    flexDirection: 'row',

    // alignItems: 'center',

    // justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
  }
});

答案 1 :(得分:0)

当您拥有一个不由线程更新的非易失性变量时,可以自由地内联该变量。

在第一种情况下,JIT编译代码后,它可能不再读取该值,而是使条件始终为真。

在第二种情况下,您具有线程安全操作。 println上的System.out是一种synchronized方法。这样会增加读写障碍,并阻止JIT优化读取操作。

如果您尝试这样做,它也应该起作用。

while(true){
  synchronized("hi") { } // does nothing but add memory barriers.
  if(longVariable < 2)
    break;
}

这还会使代码减慢1000倍以上,因此在您尝试停止线程时,该方法可能尚未JIT。

简单的解决方案是使变量volatile每次都将以线程安全的方式读取。

相关问题