2014-10-15 2 views
0

두 개의 다른 스레드에서 변수에 액세스하는 동안 오류가 발생했습니다. 도움이 내 코드와 관련이 있으므로 도움을 요청하고 있습니다. 내 질문은 어떻게 두 개의 서로 다른 스레드에서 동시에 변수에 액세스 할 수 있습니다.Java의 두 개의 다른 스레드에서 동시에 변수에 액세스

내가 무엇을 가지고 :

내 모든 개체를 보유하고 ObjectHandler 있습니다. 서버에 데이터를 보내는 Client 클래스가 있습니다. 모든 로컬 변수를 렌더링하고 추적하는 게임 클래스가 있습니다.

내 클라이언트 클래스는 플레이어로 보내고 개체를 서버에 보내야하며 내 게임 클래스는 개체를 렌더링하기 위해 개체에 액세스해야합니다. 내 게임 클래스와 클라이언트 클래스에는 각각 스레드가 있습니다.

개체 처리기

public class ObjectHandler implements Serializable{ 
    private static final long serialVersionUID = 4515552114741927916L; 

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 
    private Lock readLock = readWriteLock.readLock(); 
    private Lock writeLock = readWriteLock.writeLock(); 

    //////HANDLERS////// 
    private KeyInputHandler keyhandler; 
    private CollisionHandler collisionHandler; 
    private MouseInputHandler MouseInput; 

    private Player player; 
    private ArrayList<Entity>objects; 

    public ObjectHandler(){ 
     MouseInput = new MouseInputHandler(this); 
     keyhandler = new KeyInputHandler(); 

     objects = new ArrayList<Entity>(); 
     player = new Player(40,40,20,20,ObjectID.Player,this); 
    } 

    public synchronized KeyInputHandler getKeyhandler() {return keyhandler;} 
    public synchronized CollisionHandler getCollisionHandler() {return collisionHandler;} 
    public synchronized MouseInputHandler getMouseInput() {return MouseInput;} 

    public synchronized Player getPlayer() {return player;} 
    public synchronized void setPlayer(Player player) {this.player = player;} 

    public synchronized ArrayList<Entity> getObjects() {return objects;} 
    public synchronized void setObjects(ArrayList<Entity> objects) {this.objects = objects;} 

} 

클라이언트 클래스

package com.Nickhulsey.network; 


import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.net.InetAddress; 
import java.net.Socket; 
import java.net.UnknownHostException; 

import com.Nickhulsey.game.ObjectID; 
import com.Nickhulsey.handlers.ObjectHandler; 

public class Client implements Runnable{ 

    Thread Receive; 
    ObjectHandler game; 

    private InetAddress ipAddress; 
    private Socket socket; 
    private ObjectOutputStream outToServer; 
    private ObjectInputStream inFromServer; 

    private Packet out; 
    private Packet in; 

    public Client(ObjectHandler game, String ipAddress){ 
     this.game = game; 
     in = new Packet(); 
     out = new Packet(); 
     try { 
      this.ipAddress = InetAddress.getByName(ipAddress); 
      socket = new Socket(ipAddress,9000); 
      System.out.println("Started!"); 
     } catch (UnknownHostException e) { 
     } catch (IOException e) { 
     } 
     Receive = new Thread(this); 
     Receive.start(); 
    } 

    public synchronized void run() { 

     while(true){ 
      Send(); 
      try { 
       inFromServer = new ObjectInputStream(socket.getInputStream()); 
       in = (Packet) inFromServer.readObject(); 
      } catch (IOException e) { 
      } catch (ClassNotFoundException e) { 
      } 
      //unpack our data 
      if(in != null){ 
       unPack(in); 
      } 
     } 
    } 

    public void unPack(Packet in){ 
     //unpack our connected players IF there is any 
     game.getObjects().clear(); 
     //set in's objects to game's objects 
     for(int i = 0; i < in.getObjects().size();i++){ 
      if(in.getObjects() != null){ 
       game.getObjects().add(in.getObjects().get(i)); 
      } 
     } 
    } 

    public void Send(){ 
     try { 
      outToServer = new ObjectOutputStream(socket.getOutputStream()); 
      out = new Packet(); 

      //set data for our out package 
      out.setPlayer(game.getPlayer()); 
      out.setObjects(game.getObjects()); 
      outToServer.writeObject(out); 

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

내 게임 클래스

package com.Nickhulsey.game; 

import java.awt.Canvas; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.image.BufferStrategy; 
import java.io.Serializable; 

import javax.swing.JFrame; 
import javax.swing.JOptionPane; 

import com.Nickhulsey.handlers.ObjectHandler; 
import com.Nickhulsey.network.Client; 
import com.Nickhulsey.network.Server; 

//THREADS ARE NOT SERIALIZABLE 
public class Game extends Canvas implements Runnable, Serializable{ 
    private static final long serialVersionUID = 8279766339522266301L; 

    private Thread thread; 
    private Client gameClient; 
    private Server gameServer; 

    public final int SCALE = 1; 
    public int Server; 
    boolean running = false; 

    ObjectHandler ObjectHandler; 

    public Game(){ 
     //start the game 
     ObjectHandler = new ObjectHandler(); 

     Server = JOptionPane.showConfirmDialog(null,"Run the server?","Server",JOptionPane.YES_NO_OPTION); 

     if(Server == JOptionPane.YES_OPTION){ 
      gameServer = new Server(); 
     }else{ 
      String IpConnect = JOptionPane.showInputDialog("Enter Ip to connect to.(25.156.181.27)"); 
      gameClient = new Client(ObjectHandler,IpConnect); 
     } 

    } 

    public synchronized void start() { 
     if (running) { 
      return; 
     } 
     running = true; 
     thread = new Thread(this); 
     thread.start(); 
    } 

    public synchronized void run() { 
     while (running){ 
      if(Server != JOptionPane.YES_OPTION){ 
       long lastTime = System.nanoTime(); 
       double amountOfTicks = 60; 
       double ns = 1000000000.0D/amountOfTicks; 
       double delta = 0.0D; 
       long timer = System.currentTimeMillis(); 
       int updates = 0; 
       int frames = 0; 

       while (running){ 
       long now = System.nanoTime(); 
       delta += (now - lastTime)/ns; 
       lastTime = now; 
       while (delta >= 1){ 
        tick(); 
        updates++; 
        delta -= 1; 
        render(); 
       } 

       frames++; 

       if (System.currentTimeMillis() - timer > 1000L){ 
        timer += 1000L; 
        frames = 0; 
        updates = 0; 
       } 
       } 
      } 
     } 
     //stop(); 
    } 

    public void render() { 
     BufferStrategy bs = getBufferStrategy(); 
     if (bs == null) 
     { 
      createBufferStrategy(3); 
      return; 
     } 
     Graphics g = bs.getDrawGraphics(); 

     g.setColor(Color.white); 
     g.fillRect(0,0, 5000, 5000); 

     for(int i = 0; i < ObjectHandler.getObjects().size(); i++){ 
      ObjectHandler.getObjects().get(i).Draw(g); 
     } 

     ObjectHandler.getPlayer().Draw(g); 

     g.dispose(); 
     bs.show(); 
    } 

    public void tick() { 
     //for(int i = 0; i < objects.size();i++){objects.get(i).Update(objects);} 
     ObjectHandler.getPlayer().Update(ObjectHandler.getObjects()); 
    } 


    public static void main (String [] args){ 
     JFrame window = new JFrame("A Multiplayer GAME"); 
     Game game = new Game(); 

     window.setSize(300,300); 
     game.addKeyListener(game.ObjectHandler.getKeyhandler()); 
     game.addMouseListener(game.ObjectHandler.getMouseInput()); 
     game.addMouseMotionListener(game.ObjectHandler.getMouseInput()); 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     window.setLocationRelativeTo(null); 
     window.add(game); 
     window.setVisible(true); 
     game.start(); 
    } 

    public ObjectHandler getObjectHandler() {return ObjectHandler;} 
} 

나는이 죄송합니다, 많은 것을 알고있다. 내 문제는 총알의 arraylist에 액세스하고 다른 스레드가 액세스하려고하는 동안 그것을 편집하는 것입니다. 내가 동기화 시도하고 잠금 클래스를 사용하여 시도했다. 누구든지이 문제를 해결할 방법을 제안 할 수 있습니까? 미안 진짜 질문을하지 않거나 스택 오버 플로우 가이드 라인을 따르지 않았다면, 나는 여전히 정말로 새로운 것입니다.

편집 : 오류 로그 : 당신이 ConcurrentModificationException을받을 이유는 이미 그 일을하는

Exception in thread "Thread-3" java.util.ConcurrentModificationException 
    at java.util.ArrayList.writeObject(ArrayList.java:573) 
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:950) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1482) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1413) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1159) 
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1535) 
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496) 
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1413) 
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1159) 
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:329) 
    at com.Nickhulsey.network.Client.Send(Client.java:78) 
    at com.Nickhulsey.network.Client.run(Client.java:45) 
    at java.lang.Thread.run(Thread.java:695) 
+0

실용적인 _ _Java Concurrency in Goetz 책이 유용하다는 것을 알았고, 여전히 그것을 망칠 수 있습니다. – MarsAtomic

+0

변수에 액세스하는 중에 오류가 발생한다고 말씀하셨습니다. 정확히 어떤 오류입니까? 나는 직감이 ConcurrentModificationException 있지만, 잘 모르겠습니다. –

+0

"스레드의 예외"Thread-3 "java.util.ConcurrentModificationException"은 내가받는 오류입니다. – Nichos

답변

2

how do I access a variable at the same time from two different threads?

, 즉.
예외를 미리 대비하려면 변수에 java.util.concurrent의 클래스를 사용하거나 스레드가 변수를 독점적으로 사용하는지 확인하십시오. 코드에서 objects - ObjectHandler에있는 목록은 Game.tick()Client.unpack()/Send()의 두 스레드에 의해 동시에 사용됩니다. happing에서이 문제를 방지하려면

  • synchronized(game.updateLock) { ... method code ... }

synchronized 키워드로 시작을 Client.unpack()/Send()synchronized(ObjectHandler.updateLock) { ... method code ... }

  • 시작을 Game.tick()에 ObjectHandler public final Object updateLock = new Object;
  • 에 방법을 방법을 공유 잠금 객체를 추가합니다 3 개의 동기화 된 블록 중 하나만이 주어진 시간에 실행되도록 보장합니다 (모두 동일한 개체를 사용하여 동기화됩니다).

    개체가 반드시 필요한 것은 아니며, 동기화를 위해 ObjecHandler 개체 자체를 사용할 수 있지만 잠금을 위해 별도의 개체를 사용하여 이런 종류의 경우 동기화를 명시 적으로 만드는 것이 좋습니다.

  • +0

    응답 해 주셔서 감사합니다. 그러나 Object 객체를 설명 할 수 있다고 생각하십니까? 동시 패키지와 다른 점은 무엇이며이를 통과시키는 의미는 무엇입니까? 개체 처리기 클래스에 개체를 넣을 수 있습니까? – Nichos

    +0

    Object 개체는 동기화 할 대상 일뿐입니다. 자바는 동일한 객체를 사용하여 동기화하는 다른 모든 스레드를 검색합니다. 동기화를위한 공유 객체가 없으면'synchronized'는 아무 효과가 없습니다. – vanOekel

    +0

    '(ObjectHandler.updateLock) 매개 변수를 추가하려고하면 구문 오류가 발생합니다. – Nichos

    관련 문제