Остановить текущий поток, а затем создать новый поток, который выполняет ту же операцию? - PullRequest
0 голосов
/ 31 августа 2018

Моя проблема в том, что я не могу понять, как создать поток, который «нажатием одной кнопки запускается и останавливается нажатием другой кнопки», а затем, если я нажимаю ту же кнопку запуска, запускается НОВАЯ нить это делает точно такую ​​же операцию, как первый. Так что в основном просто новый экземпляр.

В моей программе у меня есть серверное приложение с 2 кнопками и 2 текстовыми полями. После того, как пользователь ввел правильное имя пользователя и пароль, приложение «Сервер» открывает новый ServerSocket, который прослушивает клиентов, которые хотят подключиться. Это делается в отдельном потоке, чтобы предотвратить зависание графического интерфейса. После нажатия кнопки остановки поток останавливается.

Как мне заставить мою программу запустить новую тему, которая работает так же, как и первая, когда я снова нажимаю кнопку запуска в графическом интерфейсе? Должен ли я использовать цикл?

Код серверного приложения:

public class Server extends JFrame implements ActionListener {

    JLabel instructionsLabel;
    JLabel passwordLabel;
    JPasswordField passwordTF;
    JButton shutdownButton;
    JButton startupButton;
    JLabel usernameLabel;
    JTextField usernameTF;
    Thread MyThread = new Thread(new ServerRunnable());

    public Server() {
        super("Server");
        initComponents();
    }
                               // My problem is here
    public void starterMeth() {
        MyThread.start();
    }

    public void stopMeth() {
        MyThread.interrupt();
    }
                                // in these 2 methods
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        String f = "n";
        ConnectionBean cb = new ConnectionBean();

        char[] a = passwordTF.getPassword();
        String b = new String(a);
        String inputDetails = usernameTF.getText() + b;

        Iterator it = cb.getDetails().iterator();
        while (it.hasNext()) {
            Object next = it.next();
            if (inputDetails.equals(next)) {
                f = "y";
                if (source == startupButton) {
                    if (!MyThread.isInterrupted()) {
                        starterMeth();
                        JOptionPane.showMessageDialog(null,
                            "Congratulations! Server started.",
                            "Start-up Message",
                            JOptionPane.INFORMATION_MESSAGE);
                    } else {
                        JOptionPane.showMessageDialog(null,
                            "Please restart the server application.",
                            "Start-up Message",
                            JOptionPane.INFORMATION_MESSAGE);
                    }
                } else if (source == shutdownButton) {
                    stopMeth();
                    JOptionPane.showMessageDialog(null,
                        "Server shut-down successfully!",
                        "Shut-down Message",
                        JOptionPane.INFORMATION_MESSAGE);
                }
                // only resets the text fields when the correct details are entered
                passwordTF.setText("");
                usernameTF.setText("");
            }
        }
        if (f.equals("n")) {
            JOptionPane.showMessageDialog(null, "Invalid username or password.", "Alert", JOptionPane.WARNING_MESSAGE);
        }
        cb.setCloseConnection(true);
    }

    private void initComponents() {
    }
}

Мой исполняемый код:

public class ServerRunnable implements Runnable {

    @Override
    public void run() {

        try {
            ServerSocket ss = new ServerSocket(7777);

            while(true) {
                Socket cs = ss.accept();
                new ClientThread(cs).start();
        }
        } catch (IOException ex) {
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Обзор

Несмотря на то, что создание thread действительно в Java, оно не рекомендуется по многим причинам. Наиболее важным является то, что создание thread является довольно дорогостоящим и ресурсоемким. Кроме того, в стандартной библиотеке реализовано гораздо более безопасные / эффективные модели, которые можно использовать для упрощения проблемы. В этом конкретном сценарии я бы посоветовал против этой реализации из-за характера операции; повторный запуск * остановка . Обратите внимание, что thread не может быть перезапущен после того, как он запущен , и единственный способ остановить поток во время выполнения - это вызвать interrupt(). К сожалению, прерывание потока требует от разработчика реализации обработки ошибок в методе run(). Ниже мы увидим метод run() реализации Runnable или Thread.

public void run() {
    try {
        // Your connection logic would be here
        yourLogic();
    } catch (InterruptedException ie) {
        Thread.currentThread().interrupt(); // Maintain status
    }
}

Предположим, вы создали собственную реализацию thread под названием MyThreadImpl. Ниже мы увидим, как его использовать:

public void starterMeth() {
    Thread myThread = new MyThreadImpl(); // Create thread
    myThread.start(); // Start execution in parallel
}

public void stopMeth() {
    myThread.interrupt(); // Stop the thread
}

В качестве альтернативы, если вы реализуете свой собственный Runnable, как вы в этом приложении, это будет выглядеть так:

public void starterMeth() {
    Thread myThread = new Thread(new ServerRunnable()); // Create thread
    myThread.start(); // Start execution in parallel
}

public void stopMeth() {
    myThread.interrupt(); // Stop the thread
}

Хотя оба тезиса верны, существуют лучшие подходы.

Лучший подход

Я предлагаю использовать класс CompletableFuture из-за его надежной реализации и желаемого контроля. CompletableFutures использует глобальный ForkJoinPool.common() для своей многопоточности, чтобы приложение могло выполняться с большей эффективностью. Кроме того, вы можете получить Future , который находится внутри объекта, для последующего использования, вместо того, чтобы пытаться заново создавать его каждый раз. Давайте рассмотрим, как эта реализация будет работать ниже:

public class Server {
    CompletableFuture<Void> myFuture;
    ...

    public void starterMeth() {
        myFuture = new CompletableFuture<Void>(); // Create future
        myFuture.runAsync(new ServerRunnable()); // Start execution in parallel
    }

    public void stopMeth() {
        myFuture.cancel(true); // Stop the future
    }

    ...
}
0 голосов
/ 31 августа 2018

Java не позволяет перезапустить поток после того, как он завершит выполнение .

Прерывание созданного вами потока просто завершит его выполнение. Проблема здесь в том, что вы используете тот же поток, который завершил выполнение (после нажатия кнопки остановки).

Я предлагаю одно из следующего:

  1. Улучшите ваш рабочий запуск, чтобы, когда пользователь пытается нажать кнопку shutdownButton , он останавливал то, что делал, и приобретал какой-то семафор, чтобы заставить его "спать" до кнопка запуска снова нажата.
  2. (проще) Всегда создавать новую тему в starterMeth . Не забудьте проверить, запущен ли поток, и прервать его, прежде чем начинать новый поток.

Надеюсь, это поможет.

...