Я столкнулся с довольно странной проблемой, которую я могу создать при запуске Java 8. Проблема возникает, как будто какая-то ошибка синхронизации происходит в самой JVM. Он носит прерывистый характер, но легко воспроизводится (по крайней мере, в пределах моей тестовой среды). Проблема в том, что заданное значение массива уничтожается и заменяется на 0.0 при определенных обстоятельствах. В частности, в приведенном ниже коде array[0]
оценивается до 0,0 после строки new Double(r.nextDouble());
. Затем, если вы снова просмотрите содержимое array[0]
снова, оно теперь показывает, что значение будет правильным значением 1.0. Пример вывода из этого тестового примера:
claims array[0] != 1.0....array[0] = 1.0
claims array[0] now == 1.0...array[0] = 1.0`
Я запускаю 64-разрядную Windows 7 и могу воспроизвести эту проблему как внутри Eclipse, так и при компиляции из командной строки с JDK 1.8_45, 1.8_51 и 1.8_60. Я не могу создать проблему с запуском версии 1.7_51. Те же результаты были продемонстрированы и в другом 64-битном окне Windows 7.
Эта проблема появилась в большом нетривиальном программном обеспечении, но мне удалось сконденсировать ее до нескольких строк кода. Ниже приведен небольшой тестовый пример, демонстрирующий проблему. Это довольно странно выглядящий тестовый пример, но, похоже, все это необходимо для возникновения ошибки. Использование Random
не требуется - я могу заменить все r.nextDouble()
на любое двойное значение и продемонстрировать проблему. Интересно, что если someArray[0] = .45;
заменено на someArray[0] = r.nextDouble();
, я не смог бы воспроизвести проблему (хотя нет ничего особенного в .45
). Отладка Eclipse также не поможет - она меняет время настолько, что этого больше не происходит. Даже корректное выражение System.err.println()
приведет к тому, что проблема больше не появится.
Опять же, проблема прерывистая, поэтому, чтобы воспроизвести проблему, нужно несколько раз запустить этот тестовый пример. Я думаю, что больше всего мне приходилось запускать его примерно в 10 раз, прежде чем я получу результат, показанный выше. В Eclipse я даю ему секунду или два после запуска, а затем убиваю его, если этого не произошло. Из командной строки то же самое - запустите его, если не произойдет CTRL+C
, чтобы выйти и повторить попытку. Похоже, что если это произойдет, это произойдет довольно быстро.
В прошлом я сталкивался с такими проблемами, но все они были проблемы с потоками. Я не могу понять, что здесь происходит - я даже посмотрел на байт-код (который был между 1.7_51 и 1.8_45, между прочим).
Любые идеи о том, что здесь происходит?
import java.util.Random;
public class Test {
Test(){
double array[] = new double[1];
Random r = new Random();
while(true){
double someArray[] = new double[1];
double someArray2 [] = new double [2];
for(int i = 0; i < someArray2.length; i++) {
someArray2[i] = r.nextDouble();
}
// for whatever reason, using r.nextDouble() here doesn't seem
// to show the problem, but the # you use doesn't seem to matter either...
someArray[0] = .45;
array[0] = 1.0;
// commented out lines also demonstrate problem
new Double(r.nextDouble());
// new Float(r.nextDouble();
// double d = new Double(.1) * new Double(.3);
// double d = new Double(.1) / new Double(.3);
// double d = new Double(.1) + new Double(.3);
// double d = new Double(.1) - new Double(.3);
if(array[0] != 1.0){
System.err.println("claims array[0] != 1.0....array[0] = " + array[0]);
if(array[0] != 1.0){
System.err.println("claims array[0] still != 1.0...array[0] = " + array[0]);
}else {
System.err.println("claims array[0] now == 1.0...array[0] = " + array[0]);
}
System.exit(0);
}else if(r.nextBoolean()){
array = new double[1];
}
}
}
public static void main(String[] args) {
new Test();
}
}