多线程服务器 - 如何同步共享资源

时间:2015-01-05 17:40:54

标签: java android multithreading synchronization server

我正在实施服务器 - 客户端解决方案。详细地说,服务器端是用java实现的,应该是多线程的。客户端将是一个Android应用程序,它连接到java serversocket。

我已经为这个项目做了一些工作,但现在我遇到了一个问题,我无法找到解决方案。我已经研究了很多,但我找不到任何有用的答案。

这是服务器代码:

public class Server implements Runnable{

protected int serverPort = 8001;
protected ServerSocket serverSocket = null;
protected boolean isStopped = false;
protected Thread runningThread = null;
protected Vector<WorkerThread> threads;
protected volatile Vector<Player> players;
protected Vector<Game> games;

protected synchronized Vector<Player> getPlayers()
{
    return players;
}

public Server(int port)
{
    this.serverPort = port;
    this.threads = new Vector<WorkerThread>(1);
    this.games = new Vector<Game>(1);
    this.players = new Vector<Player>(1);
}

@Override
public void run() {
    System.out.println("Server starting");
    synchronized (this)
    {
        this.runningThread = Thread.currentThread();
    }
    try
    {
        openServerSocket();
        while (! isStopped())
        {
            Socket clientSocket = null;
            try
            {
                clientSocket = this.serverSocket.accept();
            }
            catch (IOException e)
            {
                if (isStopped())
                    System.out.println("Server stopped.");
                break;
            }
            this.threads.add(new WorkerThread(clientSocket));
        }
    }
    finally
    {
        for (int i=0;i<this.threads.size();i++)
            this.threads.get(i).stopThread();
        System.out.println("Server stopped");
    }
}

private void openServerSocket()
{
    try
    {
        this.serverSocket = new ServerSocket(this.serverPort);
        System.out.println("Server is listening");
    }
    catch (IOException e)
    {
        throw new RuntimeException("Cannot open port "+this.serverPort,e);
    }
}

public synchronized void stop()
{
    this.isStopped = true;
    try
    {
        this.serverSocket.close();
    }
    catch (IOException e)
    {
        throw new RuntimeException("Error closing server", e);
    }
}

private synchronized boolean isStopped()
{
    return this.isStopped;
}

public class WorkerThread extends Thread
{
    protected Socket clientSocket = null;
    protected ObjectOutputStream oos = null;
    protected ObjectInputStream ois = null;
    private Player player;
    protected ReadThread readThread;

    public WorkerThread(Socket clientSocket)
    {
        this.clientSocket = clientSocket;
        this.start();
    }

    @Override
    public void run() {


//          synchronized (players)
//          {
            int playerId = 0;
            if (getPlayers().size() > 0)
                playerId = getPlayers().get(getPlayers().size()-1).id + 1;
            player = new Player(playerId,"NoName");

            getPlayers().add(player);
//          }

        try
        {   
            oos = new ObjectOutputStream(clientSocket.getOutputStream());
            ois = new ObjectInputStream(clientSocket.getInputStream());
            System.out.println("WorkerThread and streams created!");

            readThread = new ReadThread(ois, this);
            System.out.println("ReadThread created!");

            while (this.isInterrupted() == false)
            {
                try {
                    Thread.sleep(500);
                    System.out.println("WorkerThread is waiting ...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            readThread.stopThread();

            try
            {
                oos.close();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try
            {
                ois.close();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try
            {
                clientSocket.close();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println("WorkerThread and streams destroyed!");
        }
    }

    protected synchronized void stopThread()
    {
//          synchronized (players)
        {
            getPlayers().remove(player);
        }
        System.out.println("Player removed from list");
        this.interrupt();
    }

    public void sendPackage(DataPackage p)
    {
        try {
            oos.writeObject(p);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void processPlayerPackage(PlayerPackage p)
    {

    }

    private void processStringPackage(StringPackage p)
    {
        String msg = p.data;
        System.out.println("Incoming command: " + msg);

        //Kommandos auswerten
        if (msg.equalsIgnoreCase("Start new game"))
        {
//              games.add(new Game(p));
//              sendMsg("New game created!");
//              System.out.println("New game created");
        }
        else if (msg.toLowerCase().startsWith("playername="))
        {
            String name = msg.substring("playername=".length());
            player.name = name;
            sendPackage(new StringPackage("Hallo "+name));
            System.out.println("Player send name");
        }
        else if (msg.equalsIgnoreCase("Get running games"))
        {
//              sendPackage(new StringPackage("Hallo "+name));
//              sendMsg("Running games following:");
//              sendObject(games);
//              wr.sendPackage(p);
            System.out.println("Player requested running games");
        }
        else if (msg.equalsIgnoreCase("Get player count"))
        {
//              synchronized (players)
            {
                sendPackage(new StringPackage("Playercount="+players.size()));
            }
            System.out.println("Player requested player count");
        }
        else if (msg.equalsIgnoreCase("Get active players"))
        {
//              sendMsg("Active players following:");
//              synchronized (players)
            {
                for (int i=0;i<getPlayers().size();i++)
                    System.out.println("Player" + i + ": "+getPlayers().get(i).name);
                sendPackage(new PlayerPackage(getPlayers()));
            }
            System.out.println("Player requested active players");
        }
        else if (msg.equalsIgnoreCase("Start game"))
        {
            System.out.println("Player wants to start a game");
        }
        else if (msg.equalsIgnoreCase("Logout"))
        {
            this.stopThread();
        }
        else
            System.out.println("Command could not be processed: " + msg);
    }

    protected void processPackage(DataPackage p) {
        if (p instanceof StringPackage)
        {
            processStringPackage((StringPackage) p);
        }
        else if (p instanceof PlayerPackage)
        {
            processPlayerPackage((PlayerPackage) p);
        }
        else
        {

        }
    }

}

public class ReadThread extends Thread
{
    private ObjectInputStream in;
    private WorkerThread thread;

    public ReadThread(ObjectInputStream in, WorkerThread r)
    {
        this.thread = r;
        this.in = in;
        this.start();
    }

    @Override
    public void run()
    {
        while (this.isInterrupted() == false)
        {
            try {
                DataPackage p = (DataPackage) this.in.readObject();
                if (p != null)
                    thread.processPackage(p);
            } catch (SocketException e) {
                e.printStackTrace();
                thread.stopThread();
                break;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (EOFException e) {
//                  e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("ReadThread has stopped!");
    }

    public synchronized void stopThread()
    {
        this.interrupt();
    }
}

}

问题是,每个WorkerThread似乎都有自己的服务器开头的共享变量状态。例如,如果建立了连接,则会在WorkerThread中创建一个新的Player,并从服务器添加到Vector players。在此之后,我使用包含此Player Vector的ObjectOutputStream发送一个Object。对于此数据传输,我创建了一个新类,它实现了Serializable PlayerPackage

public class PlayerPackage extends DataPackage {

private static final long serialVersionUID = -5206233636684028091L;
protected Vector<Player> data;

public PlayerPackage(Vector<Player> v)
{
    this.data = v;
}

public Vector<Player> getData() {
    return data;
}

public void setData(Vector<Player> data) {
    this.data = data;
}
}

如果有其他连接,则会创建另一个Player对象并添加到向量中。所以球员矢量现在包含两名球员。为了测试,我在发送之前打印矢量的内容。此输出是正确的,因为它打印两个连接的两个播放器。但是如果我创建并向两个连接发送新的PlayerPackage,则只有第二个和更新的连接才能获得两个玩家。第一个连接仍然只有一个Player(第一个玩家)获得一个PlayerPackage

我已经尝试使用synchronizevolatile来解决此问题,但我的尝试都没有帮助。

我知道这是很多要阅读的代码,但我认为我应该为您提供有关我特定问题的详细信息。

0 个答案:

没有答案