2016-04-21 85 views
1

我目前在下面的類工作,while循環從客戶端發送包服務器畫圖程序:運行一個循環,每次一個點添加到一個ArrayList(Java)的

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());   
      } 
     } 
    } 
} 

正如我while循環每個循環都會持續運行睡眠(100)。這按預期工作,但爲了提高效率,我希望每次在我的ArrayList位置中更改某個循環時都會運行循環,因此它不會發送不相關的軟件包。

我想要實現:

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

你試過了什麼?爲什麼它不起作用? – BeyelerStudios

+2

將這些值添加到阻塞隊列中,允許「套接字」線程從此隊列中讀取並在每個點可用時發送它們。這樣做允許客戶端添加更多點,然後「套接字」線程可以發送,但允許「套接字」線程繼續處理隊列,直到它爲空,此時它將阻塞,等待下一批「點」 。這是「生產者 - 消費者」模式的一個例子 – MadProgrammer

+0

對於它的價值,我會避免對象序列化,至少我不會序列化「整個」列表 – MadProgrammer

回答

1

您需要任何訪問(readwrite)到您的變量的位置換到一個​​塊用的情況下,一個notify()更新它,然後在你的循環您更換sleep以作爲未來一個wait

修改位置:

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

讀訪問的位置:

0123一個synchronized塊內
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; 
    } 
} 

決賽圈:

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(); 
    } 
} 
+0

讓我們希望OP不會有任何虛假的喚醒... – Bohemian

+0

雖然它可以工作,但效率不高,隨着點數增加,需要發送的數據量會增加,需要更多時間,這可能會導致UI滯後甚至停止響應,而數據被轉移 – MadProgrammer

0

而不是讓其他物體來修改你的ArrayList直接,將其變爲私有,並創建一個getter,一個setter,並且還(因爲你正在使用集合)加法器和卸妝方法。

其中,您可以通知程序的其他部分,ArrayList已更改,並且您需要發送數據包。

0

你可以創建自己的CallbackArrayList,延伸ArrayList。 添加抽象回調方法,如onAddedonRemoved

覆蓋您想要監視的內部方法ArrayList,並根據結果調用您的回調方法。

abstract class CallbackArrayList<T> extends ArrayList<T> { 
    public abstract void onAddSuccess(T object); 
    public abstract void onAddFailure(T object); 
    @Override 
    public boolean add(T object) { 
    boolean success = super.add(object); 
    if(success) { 
     onAddSuccess(object); 
    } 
    else { 
     onAddFailure(object); 
    } 
    return success; 
    } 
} 

然後指定你的列表時,你可以做

location = new CallbackArrayList<>() { 
    @Override 
    public void onAddSuccess(Point object) { 
    // handle send information to server 
    } 
    @Override 
    public void onAddFailure(Point object) { 
    // handle failure 
    } 
}; 

每當你打電話location.add(e.getPoint()),一個回調方法後來被稱爲。

1

基本上,你應該使用某種BlockingQueue,這將讓你的「窩」線程「塊」,而等待新Point s到到達。

而不是發送整個List,你應該單獨發送每個Point,這將隨着點數的增加而節省時間。

由於隊列的性質,您可以繼續添加更多點,「套接字」線程可以按照自己的步調處理它們,這將允許隊列隨着用戶的繪製而增大,但允許當用戶停下來的時候,「套接字」線程可以趕上,而不需要做任何特別的事情。

以下示例使用一Thread.sleep從隊列中用於演示目的產生每一個點的處理之間的人工延遲,很明顯,不應該使用它(Thread.sleep),但它展示了上述幾點,線程在你停止繪圖後,將繼續從隊列轉儲點到標準輸出

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Point; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseMotionAdapter; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Queue; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue; 
import java.util.concurrent.TimeUnit; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JTextArea; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

    private BlockingQueue<Point> queue; 

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

    public Test() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       queue = new LinkedBlockingQueue<>(); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TCPClient(queue)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 

       Thread t = new Thread(new Consumer(queue)); 
       t.setDaemon(true); 
       t.start(); 
      } 
     }); 
    } 

    public class TCPClient extends JPanel { 

     private JTextArea consoleOutput = new JTextArea(1, 20); 
     private Queue<Point> queue; 
     private List<Point> cache; 

     public TCPClient(Queue<Point> queue) { 
      this.queue = queue; 
      cache = new ArrayList<>(25); 
      addMouseListener(new MouseAdapter() { 
       @Override 
       public void mousePressed(MouseEvent e) { 
        queue.add(e.getPoint()); 
        cache.add(e.getPoint()); 
       } 
      }); 

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

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

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

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

    public class Consumer implements Runnable { 

     private BlockingQueue<Point> queue; 

     public Consumer(BlockingQueue<Point> queue) { 
      this.queue = queue; 
     } 

     @Override 
     public void run() { 
      while (true) { 
       try { 
        Point p = queue.poll(Long.MAX_VALUE, TimeUnit.DAYS); 
        if (p != null) { 
         System.out.println("-> Got " + p); 
         Thread.sleep(125); 
        } 
       } catch (InterruptedException ex) { 
       } 
      } 
     } 

    } 
} 
相關問題