JavaRush/Java блог/Архив info.javarush/помогите разобраться блок if в while
d9v4
15 уровень

помогите разобраться блок if в while

Статья из группы Архив info.javarush
участников
Вот фрагмент моего кода, он прекрасно компилируется и работает но вот только если убрать System.out.println(""); из цикла то ничего уже не работает, если вставить любую другую команду вместо System.out.println(""); все норм. Никак не могу понять почему. public class LDgui { static boolean flag = false; static boolean flag2 = false; private int sec = 0; JLabel label; public static void main(String[] args) { LDgui ld = new LDgui(); ld.go(); while (true) { System.out.println("");//вот это место if (flag==true) { ld.timer(); } //int i = 0; } }
Комментарии (24)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
AndreGold
Уровень 28
5 сентября 2015, 23:16
Предполагаю, что все дело в многопоточности. У вас цикл while(true) загружает полностью процессор, т.е квантовое время, которое распределяет процессор между потоками не предоставляется больше ниодному из потоков.

Если сказать просто, то поток(thread) – это путь программного выполнения. Большинство программ, написанных сегодня, запускаются одним потоком, проблемы начинают возникать, когда несколько событий или действий должны произойти в одно время. Допустим, например, программа не способна рисовать картинку пока выполняет чтение нажатия клавиш. Программа должна уделять всё своё внимание клавиатуре, вследствие чего отсутствует возможность обрабатывать более одного события одновременно. Идеальным решением для этой проблемы может служить возможность выполнения двух или более разделов программы в одно время. Потоки позволяют нам это сделать.

Вот ссылка
Grif
Уровень 11
5 сентября 2015, 23:34
Процессор да загружается, сильно… мой на 90%. Но на счёт «больше ни кому» это не так, тогда бы и вывод в консоль не спасал бы и кнопки не нажимались бы… но скорее всего на счёт потоков направление мысли верное — работа таймера при вставленной строке «System.out.println» на это может указывать.
Grif
Уровень 11
5 сентября 2015, 23:51
Кстати я для эксперимента «вайл» поменял на «фор», загрузка упала до 34%, а вот результат тот же.
AndreGold
Уровень 28
6 сентября 2015, 00:05
скорее всего любая команда, или System.out.println(); либо просто int a = 0; Да либо что, дает возможность обработать flag.

Процессор имеет кэш, таким образом, он копирует туда наиболее часто используемые переменные, области памяти, и т.д, производит какие либо манипуляции с ними, и копирует их обратно в «медленную память». Соответственно при изменении flag, другой поток не видит изменения.
AndreGold
Уровень 28
6 сентября 2015, 00:06
либо еще проще, ввести дополнительную переменную типа boolean, и с ее помощью прерывать потоки. Или вообще не париться, а реализовать интерфейс Runnable или наследоваться от Thread.
Grif
Уровень 11
6 сентября 2015, 00:17
Прямое наследование класса не помогло, почему-то у меня работает только если ставить «System.out.println()», другое типа «int a = 0» не работает.
d9v4
Уровень 15
6 сентября 2015, 00:17
Вы имеете ввиду что бы кнопка вызывала отдельный поток?
Grif
Уровень 11
6 сентября 2015, 00:21
Не знаю как правильно ответить, суть в том, что цикл работает (это показывает счётчик), а вот условие не запускает таймер (без «System.out.println()»).
d9v4
Уровень 15
6 сентября 2015, 00:24
как вариант String i = ""; у меня работает так же boolean i = true; и еще может чего
Grif
Уровень 11
6 сентября 2015, 00:25
AndreGold прав на счёт потоков, я уверен на все 90%…
Grif
Уровень 11
6 сентября 2015, 00:27
:) Не знаю причин :) Но у меня работает только при «System.out.println()» :) Никакое присвоение переменных не действует :)
AndreGold
Уровень 28
6 сентября 2015, 00:32
static volatile boolean flag = false;


Да будет вам счастье))

Обьясняю, обьясвив переменную как volatile, «мы говорим процессору, что не нужно ее копировать в кэш, а все операции производить в медленной памяти». Тогда все потоки будут видет изменение переменной flag.
d9v4
Уровень 15
6 сентября 2015, 00:32
ну это легко проверить, если убрать всю графику а вызов флага сделать из консоли то проблема как я думаю уйдет что само по себе подтвердит версию с потоками на 100%.
AndreGold
Уровень 28
6 сентября 2015, 00:32
public static void main(String[] args)
    {
        LDgui ld = new LDgui();
        ld.go();
        while (true)
        {
            if (flag==true)
            {
                ld.timer();
            }
        }
    }
d9v4
Уровень 15
6 сентября 2015, 00:33
Спасибо
Grif
Уровень 11
6 сентября 2015, 00:34
Да так и есть!!! Супер :)
d9v4
Уровень 15
5 сентября 2015, 21:08
Вот весь код если кому интересно
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * Created by de on 29.08.2015.
 */
public class LDgui
{
    static boolean flag = false;
    static boolean flag2 = false;
    private int sec = 0;

    JLabel label;

    public static void main(String[] args)
    {
        LDgui ld = new LDgui();
        ld.go();
        while (true)
        {
            //System.out.println(flag);

            if (flag==true)
            {
                ld.timer();
            }
            //int i = 0;
        }
    }

    public void go()
    {
        JFrame frame = new JFrame();
        JButton b1 = new JButton("h+");
        JButton b2 = new JButton("h-");
        JButton b3 = new JButton("m+");
        JButton b4 = new JButton("m-");
        label = new JLabel();

        b1.addActionListener(new B1());
        b2.addActionListener(new B2());
        b3.addActionListener(new B3());
        b4.addActionListener(new B4());

        JPanel panel = new JPanel();

        //.setSize(200, 100);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        frame.setBounds(1700,15,200, 100);
        //frame.setUndecorated(true);
        frame.setVisible(true);

        frame.getContentPane().add(BorderLayout.SOUTH, panel);
        frame.getContentPane().add(BorderLayout.NORTH, label);
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
        panel.add(b1);
        panel.add(b2);
        panel.add(b3);
        panel.add(b4);
        viewText();
    }

    private void setTime(int s, boolean p)
    {
        if (p){
            sec+=s;
        }else {
            sec-=s;
        }
        if (sec<0){
            System.out.println("�������");
            sec=0;
Grif
Уровень 11
5 сентября 2015, 22:14
Забавно — запустил Ваш код, всё как вы говорите, только у меня при «int x = 0» тоже ничего не происходит, а вот при «System.out.println("")» Ваш таймер исправно тикает.
Надо же :)
Попробую поразмыслить над феноменом :)
Grif
Уровень 11
5 сентября 2015, 22:51
Пока удалось докопаться до того, что сам цикл работает (я поставил счётчик, он считает в любом случае) а вот условие не срабатывает…
Grif
Уровень 11
5 сентября 2015, 23:04
Далее, если флаг включать перед самим условием, то счетчик тоже работает (не так как надо кнопка ведь ещё не нажата, но работает) следовательно, проблема в том, что по какой то пока не понятной причине изменение значение флага до условия без «System.out.println» не доходит.
khda91
Уровень 39
4 сентября 2015, 11:12
А почему считаешь, что она не работает? У тебя ведь работает бесконечный цикл.
System.out.println("")
печатает пустую строку в консоль. А так все происходит в фоне и ничего не видно.
Grif
Уровень 11
4 сентября 2015, 12:06
Что значит
прекрасно компилируется и работает
а в чём выражается
ничего уже не работает
?

представленного фрагмента кода не достаточно, чтоб оценить проблему… могу допустить, что какой-то не указанный процесс включает
flag
что в свою очередь запускает
ld.timer();
но, что должно получаться а что нет и какая тут зависимость от
System.out.println("");//вот это место
даже теоретически… не понятно по крайней мере мне.
d9v4
Уровень 15
4 сентября 2015, 21:04
Я прошу прошения за бестолковое объяснение проблемы. Данная программа представляет не сложный таймер для выключения компьютера с GUI на Swing. Так вот данный кусок кода должен ждать flag (вызывается кнопкой) а потом вызвать обратный отсчет посредством вызова метода ld.timer();.Если присутствует System.out.println(""); перед блоком if метод успешно вызывается если заменить System.out.println(""); на int x = 0; (я думаю есть и еще варианты) все тоже прекрасно но если же: закомментировать, стереть эту строчку или написать вместо ее int x; ld.timer(); запускаться отказывается. Мой вопрос заключается в том что я не могу понять почему запуск ld.timer(); зависит от этих манипуляций.
Grif
Уровень 11
5 сентября 2015, 08:28
Тяжелый случай, по идее прямых зависимостей нет.
Может быть и можно было бы грешить на какой-то вторичный эффект при
System.out.println("")
но что у него общего с
int x = 0
?

Раз вариант поведения не стандартный, может стоит как-то настроить обработку исключений? Или для чистоты эксперимента попробовать запустить свой проект на другом ПК?