WONDERGG WONDERGG - 7 months ago 21
Java Question

Run a loop everytime a Point is added to an Arraylist (Java)

I'm currently working in following class, a paint program with a while loop sending packages from client to server:

public class TCPClient extends JPanel {


public static ArrayList<Point> location = new ArrayList<>();

private JTextArea consoleOutput = new JTextArea(1,20);

public void addComponentToPane(Container pane) {
consoleOutput.setEditable(false);
}

public TCPClient() {
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
location.add(e.getPoint());
}
});

addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
location.add(e.getPoint());
repaint();
}
});
setPreferredSize(new Dimension(800, 500));
setBackground(Color.WHITE);
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);

if(location.isEmpty()){
return;
}

Point p = location.get(0);
for (int i = 1; i < location.size(); i++) {
Point q = location.get(i);
g.drawLine(p.x, p.y, q.x, q.y);
p = q;
}
}

public static void main(String argv[]) throws Exception {

InetAddress SERVERIP = InetAddress.getLocalHost();

JFrame frame = new JFrame("Drawing with friends");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TCPClient(), BorderLayout.CENTER);

JTextArea IPadress = new JTextArea(1,20);
IPadress.setEditable(false);
IPadress.append("DEVICE IP: " + SERVERIP.getHostAddress());
frame.add(IPadress, BorderLayout.SOUTH);

frame.setSize(new Dimension(800,600));
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);

while(true) {
try {
//BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
Socket clientSocket = new Socket("localhost", 9000);

ObjectOutputStream outToServer = new ObjectOutputStream(clientSocket.getOutputStream());

//ObjectInputStream inFromServer = new ObjectInputStream(clientSocket.getInputStream());

outToServer.writeObject(location);

outToServer.flush();
clientSocket.close();

Thread.sleep(100);

} catch (SocketException e) {
System.err.println(e.toString());
}
}
}
}


As it my while loop runs constantly with a sleep(100) every loop. This works as intended, however for effeciency I want the loop to run everytime something is changed in my ArrayList locations, so it doesn't send irrellevant packages.

What I'm trying to achieve:

if(change in location) {
Send information to server
}

Answer

You will need to wrap any accesses (read and write) to your variable location into a synchronized block with a notify() in case you update it and then in your loop you replace the sleep with a wait as next:

Modification of location:

synchronized (location) {
    location.add(e.getPoint());
    location.notify();
}

Read access to location:

synchronized (location) {
    if(location.isEmpty()){
        return;
    }

    Point p = location.get(0);
    for (int i = 1; i < location.size(); i++) {
        Point q = location.get(i);
        g.drawLine(p.x, p.y, q.x, q.y);
        p = q;
    }
}

Final loop inside a synchronized block:

synchronized (location) {
    while(true) {
        //BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
        Socket clientSocket = new Socket("localhost", 9000);

        ObjectOutputStream outToServer = new ObjectOutputStream(clientSocket.getOutputStream());

        //ObjectInputStream inFromServer = new ObjectInputStream(clientSocket.getInputStream());

        outToServer.writeObject(location);

        outToServer.flush();
        clientSocket.close();
        location.wait();
    }
}