Java - пустой цикл while + многопоточность застряла в моей программе - PullRequest
0 голосов
/ 02 декабря 2018

Я попросил выполнить несколько потоков - 3 потока, которые будут "бегунами" в гонке, и нажатие ENTER завершит один из потоков и вернет время, которое потребовалось ему для запуска.

Поэтому я сделал этот код -

Класс бегуна:

import java.util.*;
public class Runner extends Thread {
    Date startDate;
    long startTime;    
    String name;
    private volatile boolean flag = true;

    //This method will set flag as false
    Runner(String name)
    {
        this.name = name;
    }
    public void stopRunning()
    {
        flag = false;
    }

    @Override
    public void run()
    {
        this.startDate = new Date();
        this.startTime = this.startDate.getTime();
        System.out.println(startTime);         
        while (flag)
        {
        }
        Date d = new Date();
        System.out.println(this.name + " Stopped Running....");
        System.out.println("The time that passed is " + Long.toString((d.getTime()-this.startTime)/1000) + " secondes" );
    }
}

Основной:

import java.io.*;
public class Main {
    public static void main(String args[])
    {
        Runner run1 = new Runner("run1");
        Runner run2 = new Runner("run2");
        Runner run3 = new Runner("run3");
        run1.start();
        run2.start();
        run3.start();
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
        run1.stopRunning();
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }

        run2.stopRunning();
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
        run3.stopRunning();
    }
}

Кодпросто создайте 3 потока Runner, после чего он ожидает ввода ENTER (в моих тестах кода мне, как ни странно, приходилось получать ввод 2 раза для каждого ENTER вместо 1) после получения ввода ENTER функция stopRunning потока включена иостановка потока.

Моя проблема в том, что когда я запускаю его (на затмении), он тратит на java около 5 секунд, чтобы выполнить thread.run () для всех трех потоков, НО, когда я его тестировал, я обнаружил, что еслиЯ добавляю цикл while (flag) к классу Runner, простой вывод, такой как System.out.println (this.name), он работает нормально, а java / eclipse компилируется и запускает его немедленно

Кто-то знает, что объяснить мнечто случилось или какМогу ли я добавить это без добавления этой строки?

Большое спасибо,

Омер

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

К сожалению, я не могу воспроизвести поведение, которое вы описываете.Тем не менее, я предполагаю, что использование сигнала и ожидание или уведомление и ожидание решит проблему.Поскольку использовать уведомления и ожидание гораздо проще, я решил исправить это следующим образом:

import java.util.*;

public class Runner extends Thread {
    Date startDate;
    long startTime;    
    String name;
    private boolean flag = true;

    //This method will set flag as false
    Runner(String name)
    {
        this.name = name;
    }

    public synchronized void stopRunning()
    {
        flag = false;
        notifyAll(); //Think about if you really need the All
    }

    @Override
    public synchronized void run()
    {
        this.startDate = new Date();
        this.startTime = this.startDate.getTime();
        System.out.println(startTime);         
        while (flag) {
            try { //Just for the sake of compiling - you may think of a better solution
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace(); 
            }
        }
        Date d = new Date();
        System.out.println(this.name + " Stopped Running....");
        System.out.println("The time that passed is " + Long.toString((d.getTime()-this.startTime)/1000) + " secondes" );
    }
}

Для простоты объяснения того, что может происходить в вашей системе, представьте, что на вашем компьютере будет работать только один поток.Теперь, когда вы введете RunnerX.run, допустимым выполнением будет застревание в цикле while, поскольку нет другого потока, который мог бы изменить ваш bool-флаг.
Чтобы предотвратить это, вы хотите «сообщить ThreadRunner» об изменении потока.(Поскольку ваша программа будет ожидать только изменения флага bool, ваш текущий поток больше не нужно выполнять.) Это делается с помощью вызова wait (не так ли это интуитивно понятно?).
Теперь вам нужно только гарантировать, что уведомите поток, который все еще ожидает, что он может работать снова.Вы делаете это, звоня по номеру notify.

То, что я только что описал, не является на 100% точным, но должно дать вам представление о том, что происходит не так.Блокировки и условия действительно являются базовыми, вам, вероятно, следует расширить свои знания по этой теме, если вы хотите продолжить параллельное программирование.

0 голосов
/ 02 декабря 2018

Без while (flag) -loop ваши три потока почти сразу заканчивают работу, поскольку у них нет причин ждать после выполнения нескольких вызовов метода Run.
Это может произойти до того, как первый блок try будетВведено.

Я не проверял ваш код, но, возможно, некоторое время блокировал System.in.read, что было бы нормальным поведением, описанным в документации:

https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read()

...