Wątek (prawdopodobnie) blokuje silnik JavaFX

0

Dobry wieczór. Ponownie zwracam się do Was z prośbą o pomoc. Jestem w trakcie tworzenia prostego komunikatora (jednocześnie może rozmawiać kilka osób, każdy klient ma do dyspozycji jedno okno) z użyciem klas Socket oraz ServerSocket. Niestety, okienko klienta od razu uruchamia się zamrożone, bez tytułu i jakichkolwiek pól. Wrzucenie w komentarz uruchamiania wątku przez klasę Main skutkuje normalnym uruchomieniem okienka. Stąd wnioskuję, że wątek ClientReader w jakiś sposób blokuje silnik JavyFX. Czy jest to spowodowane przez moją próbę dostępu do pól klasy Controller? Dziękuję za wszelką pomoc.

package communicate;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    private Controller controller;
    private ClientReader clientReader;

    @Override
    public void start(Stage primaryStage) throws Exception{
        FXMLLoader loader=new FXMLLoader(getClass().getResource("communicate.fxml"));
        Parent root = loader.load();
        controller=loader.getController();
        //controller.initialize();
        primaryStage.setTitle("Projekt");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();



        clientReader=new ClientReader(controller);
        Thread cr=new Thread(clientReader);
        cr.setDaemon(true);
        cr.start();
    }


    public static void main(String[] args) {
        launch(args);
    }
}


package communicate;

import javafx.application.Platform;
import javafx.scene.control.TextArea;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;

import static java.lang.Thread.sleep;

public class ClientReader implements Runnable {
    private Socket socket;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    private ArrayList<Message> messagesIncoming;
    private ArrayList<Message> messagesOutcoming;
    private Controller ctrl;
    private TextArea conversationArea;

    ClientReader(Controller ctrl) {
        this.ctrl=ctrl;
        conversationArea=this.ctrl.getConversationArea();
        socket=ctrl.getSocket();
        messagesIncoming=new ArrayList<>();
        messagesOutcoming=new ArrayList<>();

        try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        while(true) {
            try {
                sleep(100);
                readMsgFromServer();
                printMessageToClient();
                sleep(100);
                getMessageFromClient();
                sendMsgToServer();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized void readMsgFromServer() {
        try {
            Message msg=(Message)objectInputStream.readObject();
            messagesIncoming.add(msg);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private synchronized void sendMsgToServer() {
        if(!messagesOutcoming.isEmpty()) {
            try {
                objectOutputStream.writeObject(messagesOutcoming.get(0));
                messagesOutcoming.remove(0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    synchronized void getMessageFromClient() {
        if(!ctrl.getMessagesOutcoming().isEmpty()) {
            Message msg=ctrl.getMessagesOutcoming().remove(0);
            messagesOutcoming.add(msg);
        }
    }

    synchronized void printMessageToClient() {
        if(!messagesIncoming.isEmpty()) {
            Platform.runLater(() -> {
                        Message msg = messagesIncoming.get(0);
                        messagesIncoming.remove(0);
                        conversationArea.appendText(msg.getSender() + ": " + msg.getText() + "\n");
                    }
            );
        }
    }
}


package communicate;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;

public class Controller {
    private final int port=4000;

    @FXML
    VBox pane;

    @FXML
    HBox hboxForButton;

    private ArrayList<Message> messagesOutcoming;

    private Label nameTextLabel;
    private TextField myName;
    private String myNick;
    private String addresseeNick;
    private String msgText;

    private Label addresseeNameLabel;
    private TextField addressee;

    private Label conversationAreaLabel;
    private TextArea conversationArea;

    private Label yourAnswerLabel;
    private TextField yourAnswer;

    private Button sendMsgButton;

    private Socket socket;

    //HashMap<String, TextArea> windowsTextAreas;

    public void initialize() throws Exception {
        //windowsTextAreas=new HashMap<>();

        socket=new Socket(InetAddress.getLocalHost(), port);

        nameTextLabel=new Label("Twój myNick:");
        myName=new TextField();

        addresseeNameLabel=new Label("Nick Twojego rozmówcy:");
        addressee=new TextField();

        conversationAreaLabel=new Label("Rozmowa:");
        conversationArea=new TextArea();

        yourAnswerLabel=new Label("Twoja odpowiedź:");
        yourAnswer=new TextField();

        //dodaję elementy, ustawiam odległości pomiędzy elementami oraz akapity
        pane.getChildren().addAll(nameTextLabel, myName, addresseeNameLabel, addressee,
                conversationAreaLabel, conversationArea, yourAnswerLabel, yourAnswer);
        pane.setSpacing(10);  //tylko dla HBox lub VBox!
        pane.setPadding(new Insets(10));

        sendMsgButton =new Button("Wyślij");
        sendMsgButton.setAlignment(Pos.CENTER_RIGHT);
        HBox.setHgrow(sendMsgButton, Priority.ALWAYS);
        hboxForButton.getChildren().add(sendMsgButton);
        hboxForButton.setPadding(new Insets(10));

        sendMsgButton.setOnAction(new EventHandler<ActionEvent>() {
            //tu muszę odczytać dane z pól tekstowych

            @Override
            public void handle(ActionEvent actionEvent) {
                send(actionEvent);
            }
        });
    }

    private synchronized void send(ActionEvent event) {
        myNick=myName.getText();
        addresseeNick=addressee.getText();
        msgText=yourAnswer.getText();

        conversationArea.appendText("Ty: "+msgText+"\n");

        messagesOutcoming.add(new Message(myNick, addresseeNick, msgText));


    }

    /*HashMap<String, TextArea> getWindowsTextAreas() {
        return windowsTextAreas;
    }*/

    TextArea getConversationArea() {
        return conversationArea;
    }

    ArrayList<Message> getMessagesOutcoming() {
        return messagesOutcoming;
    }

    Socket getSocket() {
        return socket;
    }
}


package communicate;

import java.io.Serializable;

public class Message implements Serializable {

    private final String sender;
    private final String addressee;
    private final String text;

    /**
     *
     * @param sender nazwa (ID) nadawcy
     * @param addressee nazwa (ID) adresata
     */
    public Message(String sender, String addressee, String text) {
        this.sender=sender;
        this.addressee=addressee;
        this.text=text;
    }

    String getSender() {
        return sender;
    }

    String getAddressee() {
        return addressee;
    }

    String getText() {
        return text;
    }
}


package communicate;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import static java.lang.Thread.sleep;

public class Server implements Runnable {
    //private ArrayList<Message> messages;
    private Socket sock;
    private String ID;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    ArrayList<Message> messages;

    /*Server(String ID) {
        this.ID=ID;
    }*/

    Server(ArrayList<Message> msg, Socket sock) throws IOException {
        messages=msg;
        this.sock=sock;
        objectInputStream=new ObjectInputStream(sock.getInputStream());
        objectOutputStream=new ObjectOutputStream(sock.getOutputStream());
    }

    @Override
    public void run() {

        while(true) {
            try {
                sleep(100);
                receiveMsg();

                sleep(100);
                sendMsg();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }


        }
    }

    synchronized void sendMsg() {   //ten sychronized do przemyślenia!
        if(!messages.isEmpty()) {
            for (Message x : messages) {
                if (x.getAddressee().equals(ID)) {
                    //wyślij
                    try {
                        objectOutputStream.writeObject(x);
                        //objectOutputStream.flush();
                        messages.remove(x);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }


                    break;
                }
            }
        }
        /*if(messages.containsKey(ID)) {
            //wyślij
        }*/
    }

    synchronized void receiveMsg() {
        try {
            Message msg=(Message)objectInputStream.readObject();
            messages.add(msg);
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        final int port=4000;
        final int maxUsers=50;

        ArrayList<Thread> serverThreads=new ArrayList<>();
        ArrayList<Message> messages = new ArrayList<>();
        //HashMap<String, Message> messages=new HashMap<>();
        ServerSocket servSocket;
        ArrayList<Socket> users=new ArrayList<>();
        int i=0;

        System.out.println("Serwer uruchomiony");

        //try {
             servSocket = new ServerSocket(port, maxUsers);
        /*}
        catch (IOException e) {
            e.printStackTrace();
            System.out.println("Nie udało się utworzyć gniazda");
            System.exit(1);
        }*/

        /*class messagesHandler implements Runnable {

            private ArrayList<Thread> servers;
            private ArrayList<String> messages;

            messagesHandler(ArrayList<Thread> serv, ArrayList<String> msg) {
                servers=serv;
                messages=msg;
            }

            @Override
            public void run() {
                while(true) {
                    //odbieram i wysyłam wiadomości
                }
            }
        }*/

        while(true) {
            users.add(servSocket.accept());
            addUser(serverThreads, messages, users.get(i));
            serverThreads.get(i).setDaemon(true);
            serverThreads.get(i).start();
            ++i;
            //fajnie byłoby wysłać wszystkim nową listę użytkowników, ale to potem - niech się domyślają xD
        }
    }

    private void addMessage() {

    }

    private static synchronized void addUser(ArrayList<Thread> servers, ArrayList<Message> msg, Socket sock) {
        try {
            servers.add(new Thread(new Server(msg, sock)));
        }
        catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}



<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane fx:controller="communicate.Controller"
            xmlns:fx="http://javafx.com/fxml" prefWidth="512" prefHeight="512">

    <top>

    </top>

    <center>
        <VBox fx:id="pane" prefWidth="512" prefHeight="512" />
    </center>

    <bottom>
        <HBox fx:id="hboxForButton" prefWidth="512" prefHeight="100">

        </HBox>
    </bottom>

</BorderPane>
0

Jeśli masz zamrożony główny wątek JavaFX to zamiast debugować w głowie możesz zrobić zrzut wątków. Wygugluj "java thread dump" albo posłuż się czymś wbudowanym w IDE. Dla przykładu IntelliJ ma guziczek do robienia zrzutów wątków: https://www.jetbrains.com/help/idea/run-tool-window.html

Dump Threads
Ctrl+Break
Click this button to dump all threads of the current process showing their status in the Sun format.

Stworzyłem mały programik w Javie do zademonstrowania blokowania głównego wątku JavaFX. W głównym wątku wywoływane są przede wszystkim wszystkie EventHandlery, więc jeśli w jednym z nich zrobię Thread.sleep(duża liczba) to zablokuję całe GUI. Gotowy kod:

package javafx;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class BlockingGui extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Example of JavaFX thread blocking");
        Button btn = new Button();
        btn.setText("Block JavaFX thread");
        btn.setOnAction(event -> {
            try {
                Thread.sleep(Long.MAX_VALUE);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }
}

Kliknąłem przycisk, który zamraża GUI, upewniłem się, że jest zamrożone i wtedy zrobiłem thread dumpa. Oto thread dump:

2019-01-22 21:26:47
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.201-b09 mixed mode):

"Attach Listener" #16 daemon prio=9 os_prio=0 tid=0x00007f88b4001000 nid=0x1b65 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Prism Font Disposer" #15 daemon prio=10 os_prio=0 tid=0x00007f886c178800 nid=0x1b60 in Object.wait() [0x00007f8867aab000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000071af4e8d0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
	- locked <0x000000071af4e8d0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
	at com.sun.javafx.font.Disposer.run(Disposer.java:93)
	at java.lang.Thread.run(Thread.java:748)

"JavaFX-Launcher" #14 prio=5 os_prio=0 tid=0x00007f88fc5a2800 nid=0x1b5c waiting on condition [0x00007f887c5c9000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000071a129448> (a java.util.concurrent.CountDownLatch$Sync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
	at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
	at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:873)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$412(LauncherImpl.java:182)
	at com.sun.javafx.application.LauncherImpl$$Lambda$55/942731712.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

"JavaFX Application Thread" #13 prio=5 os_prio=0 tid=0x00007f88fc552000 nid=0x1b5a waiting on condition [0x00007f8894161000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at javafx.BlockingGui.lambda$start$0(BlockingGui.java:21)
	at javafx.BlockingGui$$Lambda$76/2120038659.handle(Unknown Source)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
	at javafx.event.Event.fireEvent(Event.java:198)
	at javafx.scene.Node.fireEvent(Node.java:8411)
	at javafx.scene.control.Button.fire(Button.java:185)
	at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
	at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.event.Event.fireEvent(Event.java:198)
	at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
	at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
	at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
	at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$345(GlassViewEventHandler.java:432)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$107/46572789.get(Unknown Source)
	at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
	at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
	at com.sun.glass.ui.View.notifyMouse(View.java:937)
	at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
	at com.sun.glass.ui.gtk.GtkApplication.lambda$null$203(GtkApplication.java:139)
	at com.sun.glass.ui.gtk.GtkApplication$$Lambda$41/292938459.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)

"Thread-1" #12 daemon prio=5 os_prio=0 tid=0x00007f88fc59a800 nid=0x1b57 waiting on condition [0x00007f88bc122000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000007198c8808> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:492)
	at com.sun.glass.ui.InvokeLaterDispatcher.run(InvokeLaterDispatcher.java:108)

"QuantumRenderer-0" #10 daemon prio=5 os_prio=0 tid=0x00007f88fc491800 nid=0x1b4d waiting on condition [0x00007f88e1f53000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000007197f72a8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:125)
	at java.lang.Thread.run(Thread.java:748)

"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f88fc39c000 nid=0x1b4b runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread2" #8 daemon prio=9 os_prio=0 tid=0x00007f88fc397800 nid=0x1b4a waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread1" #7 daemon prio=9 os_prio=0 tid=0x00007f88fc393800 nid=0x1b49 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #6 daemon prio=9 os_prio=0 tid=0x00007f88fc392000 nid=0x1b48 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=0 tid=0x00007f88fc38f000 nid=0x1b47 runnable [0x00007f88e2807000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0(Native Method)
	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
	at java.net.SocketInputStream.read(SocketInputStream.java:171)
	at java.net.SocketInputStream.read(SocketInputStream.java:141)
	at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
	at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
	at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
	- locked <0x0000000718fbcba0> (a java.io.InputStreamReader)
	at java.io.InputStreamReader.read(InputStreamReader.java:184)
	at java.io.BufferedReader.fill(BufferedReader.java:161)
	at java.io.BufferedReader.readLine(BufferedReader.java:324)
	- locked <0x0000000718fbcba0> (a java.io.InputStreamReader)
	at java.io.BufferedReader.readLine(BufferedReader.java:389)
	at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 tid=0x00007f88fc182000 nid=0x1b44 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f88fc14f000 nid=0x1b3f in Object.wait() [0x00007f88e2fee000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x0000000718d08ed0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
	- locked <0x0000000718d08ed0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)

"Reference Handler" #2 daemon prio=10 os_prio=0 tid=0x00007f88fc14c000 nid=0x1b3e in Object.wait() [0x00007f88e30ef000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x0000000718d06bf8> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:502)
	at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
	- locked <0x0000000718d06bf8> (a java.lang.ref.Reference$Lock)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)

"main" #1 prio=5 os_prio=0 tid=0x00007f88fc00d800 nid=0x1b31 waiting on condition [0x00007f8901f55000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000071991add0> (a java.util.concurrent.CountDownLatch$Sync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
	at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
	at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:200)
	at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:143)
	at javafx.application.Application.launch(Application.java:252)
	at javafx.BlockingGui.main(BlockingGui.java:11)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
	at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)

"VM Thread" os_prio=0 tid=0x00007f88fc142800 nid=0x1b3b runnable 

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f88fc023000 nid=0x1b34 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f88fc024800 nid=0x1b36 runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f88fc026800 nid=0x1b37 runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f88fc028000 nid=0x1b38 runnable 

"VM Periodic Task Thread" os_prio=0 tid=0x00007f88fc39f000 nid=0x1b4c waiting on condition 

JNI global references: 563

Heap
 PSYoungGen      total 150016K, used 46450K [0x0000000718d00000, 0x0000000723400000, 0x00000007c0000000)
  eden space 129024K, 36% used [0x0000000718d00000,0x000000071ba5caf8,0x0000000720b00000)
  from space 20992K, 0% used [0x0000000721f80000,0x0000000721f80000,0x0000000723400000)
  to   space 20992K, 0% used [0x0000000720b00000,0x0000000720b00000,0x0000000721f80000)
 ParOldGen       total 343040K, used 0K [0x00000005ca600000, 0x00000005df500000, 0x0000000718d00000)
  object space 343040K, 0% used [0x00000005ca600000,0x00000005ca600000,0x00000005df500000)
 Metaspace       used 12941K, capacity 13404K, committed 13696K, reserved 1060864K
  class space    used 1720K, capacity 1888K, committed 1920K, reserved 1048576K

Najważniejszy kawałek tego zrzutu wątków to:

"JavaFX Application Thread" #13 prio=5 os_prio=0 tid=0x00007f88fc552000 nid=0x1b5a waiting on condition [0x00007f8894161000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at javafx.BlockingGui.lambda$start$0(BlockingGui.java:21)
	at javafx.BlockingGui$$Lambda$76/2120038659.handle(Unknown Source)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
...
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$203(GtkApplication.java:139)
    at com.sun.glass.ui.gtk.GtkApplication$$Lambda$41/292938459.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:748)

Widać w nim, że wątek główny JavyFX nazwany "JavaFX Application Thread" wisi sobie na wstawionym przeze mnie Thread.sleep.

W momencie, gdy wątek główny JavyFX nie jest przyblokowany to jego zrzut wygląda tak:

"JavaFX Application Thread" #13 prio=5 os_prio=0 tid=0x00007fec185ae800 nid=0x1d79 runnable [0x00007feb9ccc9000]
   java.lang.Thread.State: RUNNABLE
	at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
	at com.sun.glass.ui.gtk.GtkApplication.lambda$null$203(GtkApplication.java:139)
	at com.sun.glass.ui.gtk.GtkApplication$$Lambda$41/292938459.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:748)
0

Mój thread dump wygląda w ten sposób:

Full thread dump OpenJDK 64-Bit Server VM (11.0.1+13-Ubuntu-2ubuntu1 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007f7e740321e0, length=16, elements={
0x00007f7ed4013000, 0x00007f7ed416f800, 0x00007f7ed4179800, 0x00007f7ed417e800,
0x00007f7ed4181000, 0x00007f7ed4183000, 0x00007f7ed4185000, 0x00007f7ed41e5000,
0x00007f7ed42bb000, 0x00007f7ed42be000, 0x00007f7ed433e000, 0x00007f7e8c001000,
0x00007f7ed453f000, 0x00007f7ed4627800, 0x00007f7ed4538000, 0x00007f7e383e0000
}

"main" #1 prio=5 os_prio=0 cpu=590,24ms elapsed=25,37s tid=0x00007f7ed4013000 nid=0x1a41 waiting on condition  [0x00007f7ed91aa000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x000000008c6a1e18> (a java.util.concurrent.CountDownLatch$Sync)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt([email protected]/AbstractQueuedSynchronizer.java:885)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1039)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1345)
	at java.util.concurrent.CountDownLatch.await([email protected]/CountDownLatch.java:232)
	at com.sun.javafx.application.LauncherImpl.launchApplication(javafx.graphics/LauncherImpl.java:213)
	at com.sun.javafx.application.LauncherImpl.launchApplication(javafx.graphics/LauncherImpl.java:156)
	at javafx.application.Application.launch(javafx.graphics/Application.java:296)
	at communicate.Main.main(Main.java:34)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke([email protected]/Method.java:566)
	at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(javafx.graphics/LauncherImpl.java:464)
	at com.sun.javafx.application.LauncherImpl.launchApplication(javafx.graphics/LauncherImpl.java:363)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke([email protected]/Method.java:566)
	at sun.launcher.LauncherHelper$FXHelper.main([email protected]/LauncherHelper.java:1051)

"Reference Handler" #2 daemon prio=10 os_prio=0 cpu=0,34ms elapsed=25,36s tid=0x00007f7ed416f800 nid=0x1a4d waiting on condition  [0x00007f7ead6fc000]
   java.lang.Thread.State: RUNNABLE
	at java.lang.ref.Reference.waitForReferencePendingList([email protected]/Native Method)
	at java.lang.ref.Reference.processPendingReferences([email protected]/Reference.java:241)
	at java.lang.ref.Reference$ReferenceHandler.run([email protected]/Reference.java:213)

"Finalizer" #3 daemon prio=8 os_prio=0 cpu=0,28ms elapsed=25,36s tid=0x00007f7ed4179800 nid=0x1a4e in Object.wait()  [0x00007f7ead5fb000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x0000000085056518> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:155)
	- waiting to re-lock in wait() <0x0000000085056518> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:176)
	at java.lang.ref.Finalizer$FinalizerThread.run([email protected]/Finalizer.java:170)

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 cpu=0,42ms elapsed=25,36s tid=0x00007f7ed417e800 nid=0x1a50 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 cpu=1640,27ms elapsed=25,36s tid=0x00007f7ed4181000 nid=0x1a51 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"C1 CompilerThread0" #7 daemon prio=9 os_prio=0 cpu=901,57ms elapsed=25,35s tid=0x00007f7ed4183000 nid=0x1a57 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"Sweeper thread" #8 daemon prio=9 os_prio=0 cpu=9,02ms elapsed=25,34s tid=0x00007f7ed4185000 nid=0x1a5b runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Common-Cleaner" #9 daemon prio=8 os_prio=0 cpu=0,48ms elapsed=25,26s tid=0x00007f7ed41e5000 nid=0x1a5f in Object.wait()  [0x00007f7e83ffe000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x000000008bd4f970> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:155)
	- waiting to re-lock in wait() <0x000000008bd4f970> (a java.lang.ref.ReferenceQueue$Lock)
	at jdk.internal.ref.CleanerImpl.run([email protected]/CleanerImpl.java:148)
	at java.lang.Thread.run([email protected]/Thread.java:834)
	at jdk.internal.misc.InnocuousThread.run([email protected]/InnocuousThread.java:134)

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=0 cpu=14,03ms elapsed=24,95s tid=0x00007f7ed42bb000 nid=0x1a64 runnable  [0x00007f7e83dfc000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0([email protected]/Native Method)
	at java.net.SocketInputStream.socketRead([email protected]/SocketInputStream.java:115)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:168)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:140)
	at sun.nio.cs.StreamDecoder.readBytes([email protected]/StreamDecoder.java:284)
	at sun.nio.cs.StreamDecoder.implRead([email protected]/StreamDecoder.java:326)
	at sun.nio.cs.StreamDecoder.read([email protected]/StreamDecoder.java:178)
	- locked <0x0000000085057118> (a java.io.InputStreamReader)
	at java.io.InputStreamReader.read([email protected]/InputStreamReader.java:185)
	at java.io.BufferedReader.fill([email protected]/BufferedReader.java:161)
	at java.io.BufferedReader.readLine([email protected]/BufferedReader.java:326)
	- locked <0x0000000085057118> (a java.io.InputStreamReader)
	at java.io.BufferedReader.readLine([email protected]/BufferedReader.java:392)
	at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Service Thread" #11 daemon prio=9 os_prio=0 cpu=0,13ms elapsed=24,93s tid=0x00007f7ed42be000 nid=0x1a65 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"QuantumRenderer-0" #12 daemon prio=5 os_prio=0 cpu=221,26ms elapsed=24,67s tid=0x00007f7ed433e000 nid=0x1a67 waiting on condition  [0x00007f7e83af8000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x000000008bd4ed68> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await([email protected]/AbstractQueuedSynchronizer.java:2081)
	at java.util.concurrent.LinkedBlockingQueue.take([email protected]/LinkedBlockingQueue.java:433)
	at java.util.concurrent.ThreadPoolExecutor.getTask([email protected]/ThreadPoolExecutor.java:1054)
	at java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1114)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:628)
	at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(javafx.graphics/QuantumRenderer.java:125)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"Attach Listener" #13 daemon prio=9 os_prio=0 cpu=35,16ms elapsed=24,25s tid=0x00007f7e8c001000 nid=0x1a6c runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"InvokeLaterDispatcher" #15 daemon prio=5 os_prio=0 cpu=0,87ms elapsed=24,00s tid=0x00007f7ed453f000 nid=0x1a73 in Object.wait()  [0x00007f7e561aa000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x000000008ca5ab88> (a java.lang.StringBuilder)
	at java.lang.Object.wait([email protected]/Object.java:328)
	at com.sun.glass.ui.InvokeLaterDispatcher.run(javafx.graphics/InvokeLaterDispatcher.java:127)
	- waiting to re-lock in wait() <0x000000008ca5ab88> (a java.lang.StringBuilder)

"JavaFX Application Thread" #16 prio=5 os_prio=0 cpu=1189,64ms elapsed=23,99s tid=0x00007f7ed4627800 nid=0x1a75 runnable  [0x00007f7e560a7000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0([email protected]/Native Method)
	at java.net.SocketInputStream.socketRead([email protected]/SocketInputStream.java:115)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:168)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:140)
	at java.io.ObjectInputStream$PeekInputStream.read([email protected]/ObjectInputStream.java:2745)
	at java.io.ObjectInputStream$PeekInputStream.readFully([email protected]/ObjectInputStream.java:2761)
	at java.io.ObjectInputStream$BlockDataInputStream.readShort([email protected]/ObjectInputStream.java:3258)
	at java.io.ObjectInputStream.readStreamHeader([email protected]/ObjectInputStream.java:873)
	at java.io.ObjectInputStream.<init>([email protected]/ObjectInputStream.java:350)
	at communicate.ClientReader.<init>(ClientReader.java:31)
	at communicate.Main.start(Main.java:26)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(javafx.graphics/LauncherImpl.java:846)
	at com.sun.javafx.application.LauncherImpl$$Lambda$106/0x00000008400d1040.run(javafx.graphics/Unknown Source)
	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(javafx.graphics/PlatformImpl.java:455)
	at com.sun.javafx.application.PlatformImpl$$Lambda$98/0x00000008400bd840.run(javafx.graphics/Unknown Source)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(javafx.graphics/PlatformImpl.java:428)
	at com.sun.javafx.application.PlatformImpl$$Lambda$101/0x00000008400bd440.run(javafx.graphics/Unknown Source)
	at java.security.AccessController.doPrivileged([email protected]/Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(javafx.graphics/PlatformImpl.java:427)
	at com.sun.javafx.application.PlatformImpl$$Lambda$99/0x00000008400bdc40.run(javafx.graphics/Unknown Source)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(javafx.graphics/InvokeLaterDispatcher.java:96)
	at com.sun.glass.ui.gtk.GtkApplication._runLoop(javafx.graphics/Native Method)
	at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(javafx.graphics/GtkApplication.java:277)
	at com.sun.glass.ui.gtk.GtkApplication$$Lambda$89/0x00000008400bb840.run(javafx.graphics/Unknown Source)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"JavaFX-Launcher" #17 prio=5 os_prio=0 cpu=1,96ms elapsed=23,88s tid=0x00007f7ed4538000 nid=0x1a77 waiting on condition  [0x00007f7e55fa8000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x000000008c508850> (a java.util.concurrent.CountDownLatch$Sync)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt([email protected]/AbstractQueuedSynchronizer.java:885)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1039)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1345)
	at java.util.concurrent.CountDownLatch.await([email protected]/CountDownLatch.java:232)
	at com.sun.javafx.application.PlatformImpl.runAndWait(javafx.graphics/PlatformImpl.java:466)
	at com.sun.javafx.application.PlatformImpl.runAndWait(javafx.graphics/PlatformImpl.java:440)
	at com.sun.javafx.application.LauncherImpl.launchApplication1(javafx.graphics/LauncherImpl.java:839)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(javafx.graphics/LauncherImpl.java:195)
	at com.sun.javafx.application.LauncherImpl$$Lambda$103/0x00000008400d0040.run(javafx.graphics/Unknown Source)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"Prism Font Disposer" #19 daemon prio=10 os_prio=0 cpu=0,17ms elapsed=22,61s tid=0x00007f7e383e0000 nid=0x1a7d in Object.wait()  [0x00007f7e558d2000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x000000008aca5dc8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:155)
	- waiting to re-lock in wait() <0x000000008aca5dc8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:176)
	at com.sun.javafx.font.Disposer.run(javafx.graphics/Disposer.java:93)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"VM Thread" os_prio=0 cpu=14,50ms elapsed=25,37s tid=0x00007f7ed416c800 nid=0x1a4c runnable  

"GC Thread#0" os_prio=0 cpu=15,63ms elapsed=25,38s tid=0x00007f7ed4028800 nid=0x1a43 runnable  

"GC Thread#1" os_prio=0 cpu=2,86ms elapsed=24,29s tid=0x00007f7ea0001000 nid=0x1a6a runnable  

"GC Thread#2" os_prio=0 cpu=1,25ms elapsed=24,28s tid=0x00007f7ea0002800 nid=0x1a6b runnable  

"G1 Main Marker" os_prio=0 cpu=0,20ms elapsed=25,38s tid=0x00007f7ed4059000 nid=0x1a44 runnable  

"G1 Conc#0" os_prio=0 cpu=0,05ms elapsed=25,38s tid=0x00007f7ed405b000 nid=0x1a45 runnable  

"G1 Refine#0" os_prio=0 cpu=0,92ms elapsed=25,37s tid=0x00007f7ed40d3000 nid=0x1a47 runnable  

"G1 Young RemSet Sampling" os_prio=0 cpu=8,98ms elapsed=25,37s tid=0x00007f7ed40d5000 nid=0x1a49 runnable  
"VM Periodic Task Thread" os_prio=0 cpu=30,14ms elapsed=24,93s tid=0x00007f7ed42c0800 nid=0x1a66 waiting on condition  

JNI global refs: 27, weak refs: 0

Heap
 garbage-first heap   total 129024K, used 43337K [0x0000000085000000, 0x0000000100000000)
  region size 1024K, 43 young (44032K), 2 survivors (2048K)
 Metaspace       used 14629K, capacity 15653K, committed 16000K, reserved 1062912K
  class space    used 2241K, capacity 2598K, committed 2688K, reserved 1048576K


Process finished with exit code 130 (interrupted by signal 2: SIGINT)

Dziwi mnie to, że JavaFX Application Thread nie jest zapauzowane.

0

Dziwi mnie to, że JavaFX Application Thread nie jest zapauzowane.

To, że jest RUNNABLE nie oznacza, że na nic nie czeka. Z dokumentacji: https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.State.html#RUNNABLE

public static final Thread.State RUNNABLE
Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

Ten fragment stosu wątku głównego JavyFX pokazuje problem:

    at java.io.ObjectInputStream$BlockDataInputStream.readShort([email protected]/ObjectInputStream.java:3258)
    at java.io.ObjectInputStream.readStreamHeader([email protected]/ObjectInputStream.java:873)
    at java.io.ObjectInputStream.<init>([email protected]/ObjectInputStream.java:350)
    at communicate.ClientReader.<init>(ClientReader.java:31)
    at communicate.Main.start(Main.java:26)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(javafx.graphics/LauncherImpl.java:846)

Konstruktor ObjectInputStream wczytuje dane z strumienia poniżej, czyli w twoim przypadku z socketa. Wczytywanie to oczywiście jest blokujące, nawet jeśli pokazywany status wątku to RUNNABLE.

Jeśli poguglujesz frazę "at java.net.SocketInputStream.socketRead0" to zauważysz, że zawsze jest poprzedzona frazą "java.lang.Thread.State: RUNNABLE".

0

Rozumiem. Rozwiązaniem więc powinno być rozdzielenie w jakiś sposób socketa lub przynajmniej InputStream'ów od tego, z czym wiąże się JavaFX? Przyznam szczerze, że dość słabo orientuję się w temacie, jeśli chodzi o połączenie wielowątkowości z JavąFX.

0

Zamrażanie GUI to nie jest cecha występująca wyłącznie w JavieFX czy ogólnie tylko w Javie. Zamrażanie GUI to cecha występują w KAŻDYM GUI toolkicie jaki tylko występuje na naszej planecie (i poprawnie działa, bo niepoprawnie działające mogą robić co chcą, nawet renderować obraz na karcie muzycznej), bo wszystkie są jednowątkowe (każdy proces ma jeden wątek na obsługę GUI). Zamrażanie GUI występuje w programach napisanych w Javie, C#, C++, JavaScripcie itd Żeby zapobiec zamrażaniu GUI trzeba po prostu nie blokować tego jednego wątku, w którym dzieje się obsługa GUI. Cały trik polega na tym, by przenieść długotrwałe obliczenia lub długotrwałe blokowanie poza wątek GUI, czyli do innego wątku.

0

Rozumiem. Muszę się w jakiś sposób pozbyć tego, co blokuje mój wątek główny. Nie bardzo wiem jednak, w jaki sposób strumienie mają wpływ na mój wątek główny. Czy w jakiś sposób związane jest to z obecnością Socketa w kontrolerze? Czy przeniesienie go do np. ClientReadera zlikwiduje blokowanie?

0

Z stacktrace:

"JavaFX Application Thread" #16 prio=5 os_prio=0 cpu=1189,64ms elapsed=23,99s tid=0x00007f7ed4627800 nid=0x1a75 runnable  [0x00007f7e560a7000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0([email protected]/Native Method)

wynika wprost, że w wątku głównym JavyFX czytasz z socketa. Dokładniej to domyślny konstruktor ObjectInputStream blokuje się na odczycie z socketa. Możesz np przenieść tworzenie ObjectInputStream poza wątek główny JavyFX albo w ogóle wymyślić inną architekturę.

Na początek możesz spróbować przenieść tworzenie ObjectInputStreamów z konstruktora ClientReader do jego metody run(). Nie wiem czy to niczego nie popsuje.

PS:
Busy loop i Thread.sleep() to nie jest profesjonalne podejście :] Ponadto ArrayLista nie jest thread-safe.

Czy w jakiś sposób związane jest to z obecnością Socketa w kontrolerze? Czy przeniesienie go do np. ClientReadera zlikwiduje blokowanie?

Przeczytaj swój thread dump jeszcze raz ze zrozumieniem. To w ClientReaderze się teraz blokuje, a konkretnie w jego konstruktorze (konstruktor w stacktrace jest widoczny jako <init>) itd Mam po 100x opisywać to co da się wyczytać ze stacktrace?

0

@niepamietamloginu:
https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm tutaj masz lekture. Generalnie od tego masz różne Runnable, ExecutorService, Callable i Service.
Pamiętaj, lepiej korzystac z Executorów zamiast tworzyć wątki ręcznie (tzn lepsze executorService.submit(task) zamiast new Thread(task).start)
Pamiętaj że możesz stworzyć nasłuchujący wątek który będzie miał pętlę ustawioną na "nieskończoność" ale przerywany z aplikacji

0

Dziękuję za materiały :)
Mam pewne problemy z załapaniem, o co w tym wszystkim chodzi. Zrozumiałem, że z Task nie mogę odnosić się do GUI oraz, że listę wątków w serwerze mógłbym zastąpić przez ExecutorService.
Prosiłbym o odpowiedzi na pytania: czy w ogóle mogę z zewnątrz wpływać na np. TextArea (chociażby dodanie nowej linii)?
Czy poprzez Task mam pobierać/wysyłać dane z socketa?
@scibi92: Czy mógłbyś rozwinąć myśl o tym nasłuchującym wątku? Chodzi o nasłuchiwanie dla pola tekstowego czy dla socketa?

EDIT: Socket wylądował w wątku, ale nic to nie zmieniło. Czyżby chodziło o to, że wywołuję go z klasy Main?

0

Prosiłbym o odpowiedzi na pytania: czy w ogóle mogę z zewnątrz wpływać na np. TextArea (chociażby dodanie nowej linii)?

Musisz to zrobić w wątku głównym JavyFX, a więc np poprzez javafx.application.Platform.runLater.

EDIT: Socket wylądował w wątku, ale nic to nie zmieniło. Czyżby chodziło o to, że wywołuję go z klasy Main?

Wklej obecną postać kodu i świeżego thread dumpa zrobionego przy zamrożonym GUI.

0

Dla oszczędności miejsca wrzucę tylko zmienione klasy:

package communicate;

import javafx.application.Platform;
import javafx.scene.control.TextArea;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;

import static java.lang.Thread.sleep;

public class ClientReader implements Runnable {
    private Socket socket;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    private ArrayList<Message> messagesIncoming;
    private ArrayList<Message> messagesOutcoming;
    private Controller ctrl;
    private TextArea conversationArea;

    private final int port=4000;


    ClientReader(Controller ctrl) throws Exception {
        this.ctrl=ctrl;
        conversationArea=this.ctrl.getConversationArea();
        //socket=ctrl.getSocket();
        socket=socket=new Socket(InetAddress.getLocalHost(), port);
        messagesIncoming=new ArrayList<>();
        messagesOutcoming=new ArrayList<>();

        try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void run() {
        while(true) {
            try {
                sleep(100);
                readMsgFromServer();
                printMessageToClient();
                sleep(100);
                getMessageFromClient();
                sendMsgToServer();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized void readMsgFromServer() {
        try {
            Message msg=(Message)objectInputStream.readObject();
            messagesIncoming.add(msg);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private synchronized void sendMsgToServer() {
        if(!messagesOutcoming.isEmpty()) {
            try {
                objectOutputStream.writeObject(messagesOutcoming.get(0));
                messagesOutcoming.remove(0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    synchronized void getMessageFromClient() {
        if(!ctrl.getMessagesOutcoming().isEmpty()) {
            Message msg=ctrl.getMessagesOutcoming().remove(0);
            messagesOutcoming.add(msg);
        }
    }

    synchronized void printMessageToClient() {
        if(!messagesIncoming.isEmpty()) {
            Platform.runLater(() -> {
                        Message msg = messagesIncoming.get(0);
                        messagesIncoming.remove(0);
                        conversationArea.appendText(msg.getSender() + ": " + msg.getText() + "\n");
                    }
            );
        }
    }
}


package communicate;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;

public class Controller {
    private final int port=4000;

    @FXML
    VBox pane;

    @FXML
    HBox hboxForButton;

    private ArrayList<Message> messagesOutcoming;

    private Label nameTextLabel;
    private TextField myName;
    private String myNick;
    private String addresseeNick;
    private String msgText;

    private Label addresseeNameLabel;
    private TextField addressee;

    private Label conversationAreaLabel;
    private TextArea conversationArea;

    private Label yourAnswerLabel;
    private TextField yourAnswer;

    private Button sendMsgButton;

    //private Socket socket;

    //HashMap<String, TextArea> windowsTextAreas;

    public void initialize() throws Exception {
        //windowsTextAreas=new HashMap<>();

        //socket=new Socket(InetAddress.getLocalHost(), port);

        nameTextLabel=new Label("Twój myNick:");
        myName=new TextField();

        addresseeNameLabel=new Label("Nick Twojego rozmówcy:");
        addressee=new TextField();

        conversationAreaLabel=new Label("Rozmowa:");
        conversationArea=new TextArea();

        yourAnswerLabel=new Label("Twoja odpowiedź:");
        yourAnswer=new TextField();

        //dodaję elementy, ustawiam odległości pomiędzy elementami oraz akapity
        pane.getChildren().addAll(nameTextLabel, myName, addresseeNameLabel, addressee,
                conversationAreaLabel, conversationArea, yourAnswerLabel, yourAnswer);
        pane.setSpacing(10);  //tylko dla HBox lub VBox!
        pane.setPadding(new Insets(10));

        sendMsgButton =new Button("Wyślij");
        sendMsgButton.setAlignment(Pos.CENTER_RIGHT);
        HBox.setHgrow(sendMsgButton, Priority.ALWAYS);
        hboxForButton.getChildren().add(sendMsgButton);
        hboxForButton.setPadding(new Insets(10));

        sendMsgButton.setOnAction(new EventHandler<ActionEvent>() {
            //tu muszę odczytać dane z pól tekstowych

            @Override
            public void handle(ActionEvent actionEvent) {
                send(actionEvent);
            }
        });
    }

    private synchronized void send(ActionEvent event) {
        myNick=myName.getText();
        addresseeNick=addressee.getText();
        msgText=yourAnswer.getText();

        conversationArea.appendText("Ty: "+msgText+"\n");

        messagesOutcoming.add(new Message(myNick, addresseeNick, msgText));


    }

    /*HashMap<String, TextArea> getWindowsTextAreas() {
        return windowsTextAreas;
    }*/

    TextArea getConversationArea() {
        return conversationArea;
    }

    ArrayList<Message> getMessagesOutcoming() {
        return messagesOutcoming;
    }

    /*Socket getSocket() {
        return socket;
    }*/
}

Po prostu wywaliłem Socket z controlera i zainicjalizowałem go w ClientReaderze.

Thread dump wygląda następująco:

2019-01-23 00:54:29
Full thread dump OpenJDK 64-Bit Server VM (11.0.1+13-Ubuntu-2ubuntu1 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007fa0301da290, length=16, elements={
0x00007fa0d0013000, 0x00007fa0d016f800, 0x00007fa0d0171800, 0x00007fa0d0176800,
0x00007fa0d0179000, 0x00007fa0d017b000, 0x00007fa0d017d000, 0x00007fa0d01c5000,
0x00007fa0d0289800, 0x00007fa0d028b800, 0x00007fa0d0374800, 0x00007fa088001000,
0x00007fa0d0629800, 0x00007fa0d05fe800, 0x00007fa0d04fc000, 0x00007fa03849f000
}

"main" #1 prio=5 os_prio=0 cpu=584,05ms elapsed=9,24s tid=0x00007fa0d0013000 nid=0x59bb waiting on condition  [0x00007fa0d67bd000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x000000008520d708> (a java.util.concurrent.CountDownLatch$Sync)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt([email protected]/AbstractQueuedSynchronizer.java:885)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1039)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1345)
	at java.util.concurrent.CountDownLatch.await([email protected]/CountDownLatch.java:232)
	at com.sun.javafx.application.LauncherImpl.launchApplication(javafx.graphics/LauncherImpl.java:213)
	at com.sun.javafx.application.LauncherImpl.launchApplication(javafx.graphics/LauncherImpl.java:156)
	at javafx.application.Application.launch(javafx.graphics/Application.java:296)
	at communicate.Main.main(Main.java:34)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke([email protected]/Method.java:566)
	at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(javafx.graphics/LauncherImpl.java:464)
	at com.sun.javafx.application.LauncherImpl.launchApplication(javafx.graphics/LauncherImpl.java:363)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0([email protected]/Native Method)
	at jdk.internal.reflect.NativeMethodAccessorImpl.invoke([email protected]/NativeMethodAccessorImpl.java:62)
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke([email protected]/DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke([email protected]/Method.java:566)
	at sun.launcher.LauncherHelper$FXHelper.main([email protected]/LauncherHelper.java:1051)

"Reference Handler" #2 daemon prio=10 os_prio=0 cpu=0,84ms elapsed=9,22s tid=0x00007fa0d016f800 nid=0x59c3 waiting on condition  [0x00007fa0d41b3000]
   java.lang.Thread.State: RUNNABLE
	at java.lang.ref.Reference.waitForReferencePendingList([email protected]/Native Method)
	at java.lang.ref.Reference.processPendingReferences([email protected]/Reference.java:241)
	at java.lang.ref.Reference$ReferenceHandler.run([email protected]/Reference.java:213)

"Finalizer" #3 daemon prio=8 os_prio=0 cpu=0,27ms elapsed=9,21s tid=0x00007fa0d0171800 nid=0x59c4 in Object.wait()  [0x00007fa0b8989000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x000000008521ae28> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:155)
	- waiting to re-lock in wait() <0x000000008521ae28> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:176)
	at java.lang.ref.Finalizer$FinalizerThread.run([email protected]/Finalizer.java:170)

"Signal Dispatcher" #4 daemon prio=9 os_prio=0 cpu=0,46ms elapsed=9,21s tid=0x00007fa0d0176800 nid=0x59c5 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"C2 CompilerThread0" #5 daemon prio=9 os_prio=0 cpu=1877,14ms elapsed=9,21s tid=0x00007fa0d0179000 nid=0x59c6 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"C1 CompilerThread0" #7 daemon prio=9 os_prio=0 cpu=916,53ms elapsed=9,21s tid=0x00007fa0d017b000 nid=0x59c7 waiting on condition  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE
   No compile task

"Sweeper thread" #8 daemon prio=9 os_prio=0 cpu=7,79ms elapsed=9,20s tid=0x00007fa0d017d000 nid=0x59c8 runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"Common-Cleaner" #9 daemon prio=8 os_prio=0 cpu=1,22ms elapsed=9,16s tid=0x00007fa0d01c5000 nid=0x59c9 in Object.wait()  [0x00007fa0b8484000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x000000008520e1b0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:155)
	- waiting to re-lock in wait() <0x000000008520e1b0> (a java.lang.ref.ReferenceQueue$Lock)
	at jdk.internal.ref.CleanerImpl.run([email protected]/CleanerImpl.java:148)
	at java.lang.Thread.run([email protected]/Thread.java:834)
	at jdk.internal.misc.InnocuousThread.run([email protected]/InnocuousThread.java:134)

"Monitor Ctrl-Break" #10 daemon prio=5 os_prio=0 cpu=13,25ms elapsed=8,82s tid=0x00007fa0d0289800 nid=0x59ce runnable  [0x00007fa0b8282000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0([email protected]/Native Method)
	at java.net.SocketInputStream.socketRead([email protected]/SocketInputStream.java:115)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:168)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:140)
	at sun.nio.cs.StreamDecoder.readBytes([email protected]/StreamDecoder.java:284)
	at sun.nio.cs.StreamDecoder.implRead([email protected]/StreamDecoder.java:326)
	at sun.nio.cs.StreamDecoder.read([email protected]/StreamDecoder.java:178)
	- locked <0x00000000854946d8> (a java.io.InputStreamReader)
	at java.io.InputStreamReader.read([email protected]/InputStreamReader.java:185)
	at java.io.BufferedReader.fill([email protected]/BufferedReader.java:161)
	at java.io.BufferedReader.readLine([email protected]/BufferedReader.java:326)
	- locked <0x00000000854946d8> (a java.io.InputStreamReader)
	at java.io.BufferedReader.readLine([email protected]/BufferedReader.java:392)
	at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)

"Service Thread" #11 daemon prio=9 os_prio=0 cpu=0,10ms elapsed=8,81s tid=0x00007fa0d028b800 nid=0x59cf runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"QuantumRenderer-0" #12 daemon prio=5 os_prio=0 cpu=207,74ms elapsed=8,28s tid=0x00007fa0d0374800 nid=0x59d6 waiting on condition  [0x00007fa0b017c000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x00000000854b37b0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await([email protected]/AbstractQueuedSynchronizer.java:2081)
	at java.util.concurrent.LinkedBlockingQueue.take([email protected]/LinkedBlockingQueue.java:433)
	at java.util.concurrent.ThreadPoolExecutor.getTask([email protected]/ThreadPoolExecutor.java:1054)
	at java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1114)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:628)
	at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(javafx.graphics/QuantumRenderer.java:125)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"Attach Listener" #13 daemon prio=9 os_prio=0 cpu=35,35ms elapsed=7,89s tid=0x00007fa088001000 nid=0x59dc runnable  [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"InvokeLaterDispatcher" #15 daemon prio=5 os_prio=0 cpu=1,14ms elapsed=7,58s tid=0x00007fa0d0629800 nid=0x59e1 in Object.wait()  [0x00007fa0b8383000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x00000000854b3ad0> (a java.lang.StringBuilder)
	at java.lang.Object.wait([email protected]/Object.java:328)
	at com.sun.glass.ui.InvokeLaterDispatcher.run(javafx.graphics/InvokeLaterDispatcher.java:127)
	- waiting to re-lock in wait() <0x00000000854b3ad0> (a java.lang.StringBuilder)

"JavaFX Application Thread" #16 prio=5 os_prio=0 cpu=1107,68ms elapsed=7,55s tid=0x00007fa0d05fe800 nid=0x59e2 runnable  [0x00007fa047786000]
   java.lang.Thread.State: RUNNABLE
	at java.net.SocketInputStream.socketRead0([email protected]/Native Method)
	at java.net.SocketInputStream.socketRead([email protected]/SocketInputStream.java:115)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:168)
	at java.net.SocketInputStream.read([email protected]/SocketInputStream.java:140)
	at java.io.ObjectInputStream$PeekInputStream.read([email protected]/ObjectInputStream.java:2745)
	at java.io.ObjectInputStream$PeekInputStream.readFully([email protected]/ObjectInputStream.java:2761)
	at java.io.ObjectInputStream$BlockDataInputStream.readShort([email protected]/ObjectInputStream.java:3258)
	at java.io.ObjectInputStream.readStreamHeader([email protected]/ObjectInputStream.java:873)
	at java.io.ObjectInputStream.<init>([email protected]/ObjectInputStream.java:350)
	at communicate.ClientReader.<init>(ClientReader.java:36)
	at communicate.Main.start(Main.java:26)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(javafx.graphics/LauncherImpl.java:846)
	at com.sun.javafx.application.LauncherImpl$$Lambda$106/0x00000008400d1040.run(javafx.graphics/Unknown Source)
	at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(javafx.graphics/PlatformImpl.java:455)
	at com.sun.javafx.application.PlatformImpl$$Lambda$99/0x00000008400bdc40.run(javafx.graphics/Unknown Source)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(javafx.graphics/PlatformImpl.java:428)
	at com.sun.javafx.application.PlatformImpl$$Lambda$101/0x00000008400bd440.run(javafx.graphics/Unknown Source)
	at java.security.AccessController.doPrivileged([email protected]/Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(javafx.graphics/PlatformImpl.java:427)
	at com.sun.javafx.application.PlatformImpl$$Lambda$100/0x00000008400bd040.run(javafx.graphics/Unknown Source)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(javafx.graphics/InvokeLaterDispatcher.java:96)
	at com.sun.glass.ui.gtk.GtkApplication._runLoop(javafx.graphics/Native Method)
	at com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(javafx.graphics/GtkApplication.java:277)
	at com.sun.glass.ui.gtk.GtkApplication$$Lambda$89/0x00000008400bb840.run(javafx.graphics/Unknown Source)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"JavaFX-Launcher" #17 prio=5 os_prio=0 cpu=2,27ms elapsed=7,37s tid=0x00007fa0d04fc000 nid=0x59e4 waiting on condition  [0x00007fa047687000]
   java.lang.Thread.State: WAITING (parking)
	at jdk.internal.misc.Unsafe.park([email protected]/Native Method)
	- parking to wait for  <0x00000000854f7a48> (a java.util.concurrent.CountDownLatch$Sync)
	at java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:194)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt([email protected]/AbstractQueuedSynchronizer.java:885)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1039)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly([email protected]/AbstractQueuedSynchronizer.java:1345)
	at java.util.concurrent.CountDownLatch.await([email protected]/CountDownLatch.java:232)
	at com.sun.javafx.application.PlatformImpl.runAndWait(javafx.graphics/PlatformImpl.java:466)
	at com.sun.javafx.application.PlatformImpl.runAndWait(javafx.graphics/PlatformImpl.java:440)
	at com.sun.javafx.application.LauncherImpl.launchApplication1(javafx.graphics/LauncherImpl.java:839)
	at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(javafx.graphics/LauncherImpl.java:195)
	at com.sun.javafx.application.LauncherImpl$$Lambda$103/0x00000008400d0040.run(javafx.graphics/Unknown Source)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"Prism Font Disposer" #19 daemon prio=10 os_prio=0 cpu=0,17ms elapsed=5,53s tid=0x00007fa03849f000 nid=0x59ec in Object.wait()  [0x00007fa046ee5000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait([email protected]/Native Method)
	- waiting on <0x000000008523c9d0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:155)
	- waiting to re-lock in wait() <0x000000008523c9d0> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove([email protected]/ReferenceQueue.java:176)
	at com.sun.javafx.font.Disposer.run(javafx.graphics/Disposer.java:93)
	at java.lang.Thread.run([email protected]/Thread.java:834)

"VM Thread" os_prio=0 cpu=12,08ms elapsed=9,23s tid=0x00007fa0d016c800 nid=0x59c1 runnable  

"GC Thread#0" os_prio=0 cpu=35,84ms elapsed=9,24s tid=0x00007fa0d0028800 nid=0x59bc runnable  

"GC Thread#1" os_prio=0 cpu=38,65ms elapsed=7,92s tid=0x00007fa09c001000 nid=0x59da runnable  

"GC Thread#2" os_prio=0 cpu=23,26ms elapsed=7,91s tid=0x00007fa09c002800 nid=0x59db runnable  

"GC Thread#3" os_prio=0 cpu=19,96ms elapsed=5,49s tid=0x00007fa09c005000 nid=0x59ed runnable  

"G1 Main Marker" os_prio=0 cpu=0,33ms elapsed=9,24s tid=0x00007fa0d0059000 nid=0x59bd runnable  

"G1 Conc#0" os_prio=0 cpu=0,05ms elapsed=9,24s tid=0x00007fa0d005b000 nid=0x59be runnable  

"G1 Refine#0" os_prio=0 cpu=15,22ms elapsed=9,24s tid=0x00007fa0d00d3000 nid=0x59bf runnable  

"G1 Refine#1" os_prio=0 cpu=0,47ms elapsed=5,46s tid=0x00007fa0a0001000 nid=0x59ee runnable  

"G1 Young RemSet Sampling" os_prio=0 cpu=1,51ms elapsed=9,24s tid=0x00007fa0d00d5000 nid=0x59c0 runnable  
"VM Periodic Task Thread" os_prio=0 cpu=7,84ms elapsed=8,81s tid=0x00007fa0d028f000 nid=0x59d0 waiting on condition  

JNI global refs: 27, weak refs: 0

Heap
 garbage-first heap   total 129024K, used 12473K [0x0000000085000000, 0x0000000100000000)
  region size 1024K, 6 young (6144K), 1 survivors (1024K)
 Metaspace       used 14610K, capacity 15717K, committed 16000K, reserved 1062912K
  class space    used 2235K, capacity 2598K, committed 2688K, reserved 1048576K


Process finished with exit code 130 (interrupted by signal 2: SIGINT)
1

Powiedz mi, dlaczego tak bardzo uparłeś się na ten Socket, skoro znowu jak na dłoni widać, że problemem jest tworzenie ObjectInputStream w głównym wątku JavyFX?

"JavaFX Application Thread" #16 prio=5 os_prio=0 cpu=1107,68ms elapsed=7,55s tid=0x00007fa0d05fe800 nid=0x59e2 runnable  [0x00007fa047786000]
   java.lang.Thread.State: RUNNABLE
    at java.net.SocketInputStream.socketRead0([email protected]/Native Method)
...
    at java.io.ObjectInputStream.<init>([email protected]/ObjectInputStream.java:350)
    at communicate.ClientReader.<init>(ClientReader.java:36)
    at communicate.Main.start(Main.java:26)
...

Gdyby wisiało na klasie Socket to byłoby to widoczne w stacktrace.

PS:
DataInputStream ma konstruktor bez efektów ubocznych. Zamień ObjectInputStream na DataInputStream i może będzie hulać.

Polecam też wyguglanie frazy "how to read java stack trace" i lekturę artykułów na ten temat.

0

DataInputStream ma konstruktor bez efektów ubocznych. Zamień ObjectInputStream na DataInputStream i może będzie hulać.

Niestety, nie mogę tak zrobić. Muszę przesyłać cały obiekt klasy Message.

1

Niestety, nie mogę tak zrobić. Muszę przesyłać cały obiekt klasy Message.

Klasa Message to 3 Stringi. Możesz je przesłać bez problemu za pomocą Data(Input/Output)Stream. W jednym miejscu wrzucasz 3 Stringi, w drugim odbierasz i montujesz z nich instancję klasy Message.

Inne rozwiązanie przedstawiłem wcześniej:

Na początek możesz spróbować przenieść tworzenie ObjectInputStreamów z konstruktora ClientReader do jego metody run().

Nie zrobiłeś tego. Zamiast tego, bez żadnego sensownego wytłumaczenia, przenosisz sobie miejsce tworzenia Socketa.

0

@Wibowit: Wybacz. Nie wiem jakim cudem nie dostrzegłem Twojego rozwiązania. Tworzenie strumieni przeniosłem do metody run(). Teraz okno odpala się normalnie, ale próba wysłania wiadomości kończy się całą listą wyjątków. Jeden błąd już wyłapałem (zapomniałem zainicjować messagesOutcoming w kontrolerze. Teraz biorę się za szukanie kolejnych.
Uświadomiłem też sobie, że samo podanie nicku do wiadomości to za mało. Skąd serwer ma wiedzieć, że któryś z klientów ma taki nick, zanim nie wyśle do kogoś wiadomości?! Prawdopodobnie zastąpię nick ID w postaci losowego inta.

2

Jeszcze jedno: antonim dla incoming to outgoing, a nie outcoming.

0

Wprowadziłem kilka zmian. Przede wszystkim ID od tej pory jest przekształconym do stringa intem (liczba losowa) i jest od razu wysyłany serwerowi tak, by odpowiedni jego wątek mógł sobie przypisać tę wartość.
Program kompiluje się i uruchamia, ale wiadomości idą w kierunku nieznanym, tj. w ogóle nie trafiają do adresata.

Całość w tej chwili prezentuje się tak:

package communicate;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    private Controller controller;
    private ClientReader clientReader;

    @Override
    public void start(Stage primaryStage) throws Exception{
        FXMLLoader loader=new FXMLLoader(getClass().getResource("communicate.fxml"));
        Parent root = loader.load();
        controller=loader.getController();
        //controller.initialize();
        primaryStage.setTitle("Projekt");
        primaryStage.setScene(new Scene(root));
        primaryStage.show();



        clientReader=new ClientReader(controller);
        Thread cr=new Thread(clientReader);
        cr.setDaemon(true);
        cr.start();
    }


    public static void main(String[] args) {
        launch(args);
    }
}


package communicate;

import javafx.application.Platform;
import javafx.scene.control.TextArea;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Random;

import static java.lang.Thread.sleep;

public class ClientReader implements Runnable {
    private Socket socket;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    private ArrayList<Message> messagesIncoming;
    private ArrayList<Message> messagesOutgoing;
    private Controller ctrl;
    private TextArea conversationArea;

    private String ID;

    private final int port=4000;


    ClientReader(Controller ctrl) throws Exception {
        this.ctrl=ctrl;
        conversationArea=this.ctrl.getConversationArea();
        //socket=ctrl.getSocket();
        socket=new Socket(InetAddress.getLocalHost(), port);
        messagesIncoming=new ArrayList<>();
        messagesOutgoing =new ArrayList<>();

        /*Random generator=new Random();
        int tempID=generator.nextInt();
        ID=Integer.toString(tempID);*/

        ID=ctrl.getID();

        /*try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        }
        catch (IOException e) {
            e.printStackTrace();
        }*/
    }

    public void run() {
        try {
            objectInputStream = new ObjectInputStream(socket.getInputStream());
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(ID);

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


        while(true) {
            try {
                sleep(100);
                readMsgFromServer();
                printMessageToClient();
                sleep(100);
                getMessageFromClient();
                sendMsgToServer();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized void readMsgFromServer() {
        try {
            Message msg=(Message)objectInputStream.readObject();
            messagesIncoming.add(msg);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    private synchronized void sendMsgToServer() {
        if(!messagesOutgoing.isEmpty()) {
            try {
                objectOutputStream.writeObject(messagesOutgoing.get(0));
                messagesOutgoing.remove(0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    synchronized void getMessageFromClient() {
        if(!ctrl.getMessagesOutgoing().isEmpty()) {
            Message msg=ctrl.getMessagesOutgoing().remove(0);
            messagesOutgoing.add(msg);
        }
    }

    synchronized void printMessageToClient() {
        if(!messagesIncoming.isEmpty()) {
            Platform.runLater(() -> {
                        Message msg = messagesIncoming.get(0);
                        messagesIncoming.remove(0);
                        conversationArea.appendText(msg.getSender() + ": " + msg.getText() + "\n");
                    }
            );
        }
    }
}


package communicate;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

import java.util.ArrayList;
import java.util.Random;

public class Controller {
    private final int port=4000;

    @FXML
    VBox pane;

    @FXML
    HBox hboxForButton;

    private ArrayList<Message> messagesOutgoing;

    private String ID;

    private Label nameTextLabel;
    private TextField myName;
    private String myNick;
    private String addresseeNick;
    private String msgText;

    private Label addresseeNameLabel;
    private TextField addressee;

    private Label conversationAreaLabel;
    private TextArea conversationArea;

    private Label yourAnswerLabel;
    private TextField yourAnswer;

    private Button sendMsgButton;

    //private Socket socket;

    //HashMap<String, TextArea> windowsTextAreas;

    public void initialize() throws Exception {
        Random generator=new Random();
        int tempID=generator.nextInt();
        ID=Integer.toString(tempID);
        //windowsTextAreas=new HashMap<>();

        //socket=new Socket(InetAddress.getLocalHost(), port);
        messagesOutgoing =new ArrayList<>();

        nameTextLabel=new Label("Twój nick:");
        myName=new TextField();
        myName.setText(ID);

        addresseeNameLabel=new Label("Nick Twojego rozmówcy:");
        addressee=new TextField();

        conversationAreaLabel=new Label("Rozmowa:");
        conversationArea=new TextArea();

        yourAnswerLabel=new Label("Twoja odpowiedź:");
        yourAnswer=new TextField();

        //dodaję elementy, ustawiam odległości pomiędzy elementami oraz akapity
        pane.getChildren().addAll(nameTextLabel, myName, addresseeNameLabel, addressee,
                conversationAreaLabel, conversationArea, yourAnswerLabel, yourAnswer);
        pane.setSpacing(10);  //tylko dla HBox lub VBox!
        pane.setPadding(new Insets(10));

        sendMsgButton =new Button("Wyślij");
        sendMsgButton.setAlignment(Pos.CENTER_RIGHT);
        HBox.setHgrow(sendMsgButton, Priority.ALWAYS);
        hboxForButton.getChildren().add(sendMsgButton);
        hboxForButton.setPadding(new Insets(10));

        sendMsgButton.setOnAction(new EventHandler<ActionEvent>() {
            //tu muszę odczytać dane z pól tekstowych

            @Override
            public void handle(ActionEvent actionEvent) {
                send(actionEvent);
            }
        });
    }

    private synchronized void send(ActionEvent event) {
        //myNick=myName.getText();
        addresseeNick=addressee.getText();
        msgText=yourAnswer.getText();

        conversationArea.appendText("Ty: "+msgText+"\n");

        messagesOutgoing.add(new Message(ID, addresseeNick, msgText));


    }

    /*HashMap<String, TextArea> getWindowsTextAreas() {
        return windowsTextAreas;
    }*/

    TextArea getConversationArea() {
        return conversationArea;
    }

    ArrayList<Message> getMessagesOutgoing() {
        return messagesOutgoing;
    }

    /*Socket getSocket() {
        return socket;
    }*/

    String getID() {
        return ID;
    }
}


package communicate;

import java.io.Serializable;

public class Message implements Serializable {

    private final String sender;
    private final String addressee;
    private final String text;

    /**
     *
     * @param sender nazwa (ID) nadawcy
     * @param addressee nazwa (ID) adresata
     */
    public Message(String sender, String addressee, String text) {
        this.sender=sender;
        this.addressee=addressee;
        this.text=text;
    }

    String getSender() {
        return sender;
    }

    String getAddressee() {
        return addressee;
    }

    String getText() {
        return text;
    }
}


package communicate;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import static java.lang.Thread.sleep;

public class Server implements Runnable {
    //private ArrayList<Message> messages;
    private Socket sock;
    private String ID;
    private ObjectInputStream objectInputStream;
    private ObjectOutputStream objectOutputStream;
    ArrayList<Message> messages;

    /*Server(String ID) {
        this.ID=ID;
    }*/

    Server(ArrayList<Message> msg, Socket sock) throws Exception {
        messages=msg;
        this.sock=sock;
        objectInputStream=new ObjectInputStream(sock.getInputStream());
        objectOutputStream=new ObjectOutputStream(sock.getOutputStream());
        ID=(String) objectInputStream.readObject();
    }

    @Override
    public void run() {

        while(true) {
            try {
                sleep(100);
                receiveMsg();

                sleep(100);
                sendMsg();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }


        }
    }

    synchronized void sendMsg() {   //ten sychronized do przemyślenia!
        if(!messages.isEmpty()) {
            for (Message x : messages) {
                if (x.getAddressee().equals(ID)) {
                    //wyślij
                    try {
                        objectOutputStream.writeObject(x);
                        //objectOutputStream.flush();
                        messages.remove(x);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }


                    break;
                }
            }
        }
        /*if(messages.containsKey(ID)) {
            //wyślij
        }*/
    }

    synchronized void receiveMsg() {
        try {
            Message msg=(Message)objectInputStream.readObject();
            messages.add(msg);
        }
        catch(Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        final int port=4000;
        final int maxUsers=50;

        ArrayList<Thread> serverThreads=new ArrayList<>();
        ArrayList<Message> messages = new ArrayList<>();
        //HashMap<String, Message> messages=new HashMap<>();
        ServerSocket servSocket;
        ArrayList<Socket> users=new ArrayList<>();
        int i=0;

        System.out.println("Serwer uruchomiony");

        //try {
             servSocket = new ServerSocket(port, maxUsers);
        /*}
        catch (IOException e) {
            e.printStackTrace();
            System.out.println("Nie udało się utworzyć gniazda");
            System.exit(1);
        }*/

        /*class messagesHandler implements Runnable {

            private ArrayList<Thread> servers;
            private ArrayList<String> messages;

            messagesHandler(ArrayList<Thread> serv, ArrayList<String> msg) {
                servers=serv;
                messages=msg;
            }

            @Override
            public void run() {
                while(true) {
                    //odbieram i wysyłam wiadomości
                }
            }
        }*/

        while(true) {
            users.add(servSocket.accept());
            addUser(serverThreads, messages, users.get(i));
            serverThreads.get(i).setDaemon(true);
            serverThreads.get(i).start();
            ++i;
            //fajnie byłoby wysłać wszystkim nową listę użytkowników, ale to potem - niech się domyślają xD
        }
    }

    private void addMessage() {

    }

    private static synchronized void addUser(ArrayList<Thread> servers, ArrayList<Message> msg, Socket sock) {
        try {
            servers.add(new Thread(new Server(msg, sock)));
        }
        catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}


<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane fx:controller="communicate.Controller"
            xmlns:fx="http://javafx.com/fxml" prefWidth="512" prefHeight="512">

    <top>

    </top>

    <center>
        <VBox fx:id="pane" prefWidth="512" prefHeight="512" />
    </center>

    <bottom>
        <HBox fx:id="hboxForButton" prefWidth="512" prefHeight="100">

        </HBox>
    </bottom>

</BorderPane>
0

Dobry wieczór. Rozwiązałem już większość problemów, pozostał tylko jeden. W jaki sposób mogę sprawdzić, czy ObjectInputStream zawiera jakiekolwiek elementy?

1 użytkowników online, w tym zalogowanych: 0, gości: 1