1 Востаннє редагувалося Lokki (22.05.2016 21:13:54)

Тема: Не завершується програма

Добрий день зіткнувся з проблемою при написанні сервера і клієнта на UDP.

Програма доходить до кінця функції мейн але не завершується.
Використовую 2 потоки ну і головний.

Код:

Мейн

public class Main {
    public static void main(String[] args) {

        final int PORT = 7771;
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        Thread thread = null, thread1 = null;
        Exchanger<String> exchanger = new Exchanger<>();
        try {
            executorService.submit(new UDPServer(PORT, exchanger));
            executorService.submit(new MessageHandler(System.out, exchanger));
        } catch (SocketException e) {
            e.printStackTrace();
        }

        BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));

        try {
            DatagramSocket clientSocket = new DatagramSocket();
            InetAddress ipAddress = InetAddress.getByName("localhost");

            while(true){
                byte[] sendData = new byte[1024];
                System.out.println("Enter text: ");
                String sentence = inFromUser.readLine();
                if(sentence.equals("quit")) {
                    executorService.shutdown();
                    break;
                }

                sendData = sentence.getBytes();
                DatagramPacket datagramPacket = new DatagramPacket(sendData, sendData.length, ipAddress, PORT);

                clientSocket.send(datagramPacket);
            }
            clientSocket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Class UDPServer

public class UDPServer extends Thread {
    private DatagramSocket datagramSocket = null;
    private DatagramPacket datagramPacket = null;
    private byte[] recieveData;
    private Exchanger<String> exchanger;

    UDPServer(int port, Exchanger ex) throws SocketException {
        super();

        datagramSocket = new DatagramSocket(port);
        recieveData = new byte[1024];
        datagramPacket = new DatagramPacket(recieveData, recieveData.length);

        exchanger = ex;
    }

    public void run(){

            try {
                while(true) {
                    datagramSocket.receive(datagramPacket);
                    String sentence = new String(datagramPacket.getData());
                    InetAddress ipAddress = datagramPacket.getAddress();
                    int port = datagramPacket.getPort();

                    exchanger.exchange("{" + ipAddress.toString()
                            + ":" + Integer.toString(port) + "} : " + sentence);
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
            finally {
                close();
            }

    }
    public void close(){
        datagramSocket.close();
    }
}

Class MeessageHandler

public class MessageHandler extends Thread {
    private Exchanger<String> exchanger;
    private PrintStream printStream = null;

    MessageHandler(PrintStream printStream, Exchanger ex){
        exchanger = ex;
        this.printStream = printStream;
    }
    public void run(){

            try {
                while(true) {

                    printStream.println(exchanger.exchange("ok"));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

    }
}

2

Re: Не завершується програма

Застосунок завершує свою роботу, коли усі non-daemon треди закінчують свою роботу.
У Вашому випадку, нитка main закінчує свою роботу при вводі "exit", натомість 2 інші продовжують працювати.

executorService.shutdownNow();

не закінчує виконання ниток, а лише "посилає" (встановлює флаг) сигнал переривання. Ви маєте самостійно перевіряти у своїх нитках, чи такий флаг встановлено (або десь вивалився InterruptedException), і якщо так, самостійно завершити виконання.
Це можна зробити, на приклад, у while(true) петлі Ваших ниток:

while (true) {
   if (Thread.currentThread().isInterrupted()) 
      break;
}

Детальніше: http://stackoverflow.com/a/10504487/2180005

Подякували: leofun011

3 Востаннє редагувалося Lokki (23.05.2016 18:50:10)

Re: Не завершується програма

Щось не працює.

if (Thread.currentThread().isInterrupted())
                break;

Повертає фолс!

4

Re: Не завершується програма

Lokki написав:

Щось не працює.

if (Thread.currentThread().isInterrupted())
                break;

Повертає фолс!

Після executorService.shutdown(); ?

5 Востаннє редагувалося Lokki (24.05.2016 01:36:26)

Re: Не завершується програма

Да

Знайшов як вирішити проблему але не знаю виглядає це дивно як на мене.

В потоках в методі run() я використовую метод класу Exhanger.exhanger(...), котрий обробляю в try-catch. Цей метод може викликати помилку InterruptedException. І в catch я роблю break;

while(!Thread.currentThread().isInterrupted()) {
            try {
                printStream.println(exchanger.exchange("ok"));
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;                        // <--
            }
        }

Але без цього блоку якщо не обробляти помилку то все працює нормально.

Хотя ні один потік закривається нормально навть без break; а один висить. Пробував два рази викликати shutdownNow() і тоді раз через раз закриваються два.

6

Re: Не завершується програма

InterruptedException викидається саме після того, як буде встановлений флаг interupted. Так теж роблять.
Спробуйте Thread.currentThread().isInterrupted() замінити на isInterrupted() просто.

7

Re: Не завершується програма

Замінив але навіть після виклику interrupt() isInterrupted() повертає false.
Не можу зрозуміти чому isInterrupted() повертає false а Thread.currentThread.isInterrupted() - true?

В результаті зупинився на цьому:

public void run(){

        while(!Thread.currentThread().isInterrupted()) {
            try {
                printStream.println(exchanger.exchange("ok"));
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();    //  <-- замість break, хоча з break-ом прграма буде працювати бистріше
            }
        }

    }

8

Re: Не завершується програма

Lokki написав:

Замінив але навіть після виклику interrupt() isInterrupted() повертає false.
Не можу зрозуміти чому isInterrupted() повертає false а Thread.currentThread.isInterrupted() - true?

В результаті зупинився на цьому:

public void run(){

        while(!Thread.currentThread().isInterrupted()) {
            try {
                printStream.println(exchanger.exchange("ok"));
            } catch (InterruptedException e) {
                e.printStackTrace();
                Thread.currentThread().interrupt();    //  <-- замість break, хоча з break-ом прграма буде працювати бистріше
            }
        }

    }

Тому що як тільки буде викинутий InterruptedException, флаг зкидається. Тому у кетчі буде Thread.currentThread().interrupt(); ~~~.
Ваш код не працює тому що ви ігноруєте InterruptedException, флаг зкидається і while знову бачить Thread.currentThread().isInterrupted() ~~ false.

Якщо Ваш код усередині кидає InterruptedException, вам не треба перевіряти стан нитки у петлі:

public void run(){

        while(true) {
            try {
                printStream.println(exchanger.exchange("ok"));
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
        }

    }

Варто також зауважити (тут і я трохи прогавив), що executorService.shutdown(); НЕ ВБИВАЄ поточні нитки. У документації сказано: Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.
Тобто цей метод блокує створення нових ниток, але не закінчує ті, що зараз виконуються.

Тож у Вашому випадку треба користуватися shutdownNow()

Подякували: leofun011

9

Re: Не завершується програма

Можливо цей приклад Вам допоможе:

public class Main {
    static class MyThread implements Runnable {
        final int myThreadId;

        MyThread(int myThreadId) {
            this.myThreadId = myThreadId;
        }

        @Override
        public void run() {
            while (true) {
                System.out.println("Thread #" + this.myThreadId + " is still alive! \n");
                try {
                    Thread.sleep(1000); // щоб було краще бачити виконання ниток
                } catch (InterruptedException e) {
                    System.out.println("Thread #" + this.myThreadId + ": Oh :( Someone killed me! \n");
                    break;
                }
            }
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        final ExecutorService executorService = Executors.newFixedThreadPool(2);

        executorService.submit(new MyThread(1));
        executorService.submit(new MyThread(2));

        Thread.sleep(3000);  // щоб прошов деякий час, перед закінченням ниток

        executorService.shutdownNow();
    }
}
Подякували: leofun011