Логика многопоточного сервера Java, ключевое слово Synchronized, проблема

#java #multithreading #sockets #synchronization

#java #многопоточность #сокеты #синхронизация

Вопрос:

Я создаю клиент-серверное приложение на Java, которое позволит нескольким людям, используя клиентское приложение swing (блокнот), подключаться к серверу. После подключения каждый клиент должен будет запросить управление блокнотом, чтобы они могли редактировать его, а затем отказаться от управления, отправив свой результат для отображения на панели всех других клиентов.

Основная проблема, с которой я сталкиваюсь, — это многопоточная серверная логика, использующая экземпляр основного сервера и несколько потоков, каждый из которых обрабатывает связь с клиентом.

Я не уверен, будет ли работать выбранная мной структура или возникнет какая-то проблема, связанная с моим непониманием того, как работают потоки, что приведет к повреждению данных или какой-либо другой проблеме, связанной с потоком.

в любом случае, это серверный код, мне было интересно, может ли кто-нибудь сказать мне, будет ли эта система работать без ошибок? Конечно, можно добавить больше логики, например, ограничение количества подключений, список ожидания блокировки и т.д. Но меня в основном интересует связь между потоками.

Мне также интересно, как получить доступ к методам экземпляра сервера изнутри потока, поскольку я не уверен. — обратите внимание, что это было выяснено, я использую общий объект «lock», который содержит список экземпляров потока, и у каждого экземпляра потока есть экземпляр lock, поэтому они могут вызывать методы друг у друга.

большое спасибо.

 import java.net.*;
import java.io.*;
import java.util.ArrayList;


public class server {

    private ArrayList<ClientServiceThread> SocketList;
    private int lock = 0;
    private ServerSocket myServerSocket;
    private Socket mySocket;

    public static void main(String[] args)
    {
        server myserver = new server();
    }

    public server()
    {

        /**
         * This will (when finished) accept only a certain number of connections,
         * and will then finish the constructor by breaking the while loop. It will
         * then sit here waiting for the synchronised methods to be called by its worker 
         * threads.
         */
        try{

            myServerSocket = new ServerSocket(8080);

        }catch(Exception e)
        {
            System.out.println("Could not create serversocket " e);
        }

        int id = 1;
        while(true)
        {
            try{

                mySocket = myServerSocket.accept();
                ClientServiceThread cliThread = new ClientServiceThread(mySocket, id);
                SocketList.add(cliThread);
                id  ;
                cliThread.start();

            }catch(Exception e)
            {
                System.out.println("Problem with accepting connections");
            }

        }

    }//end constructor


    public synchronized boolean acquireLock(int id)
    {
        /**
         * Here any spawned thread can try to acquire the lock, 
         * so it can be the one to send the data (synchronised to prevent data corruption) 
         */

        if(this.lock == 0){
            this.lock = id;
            return true;
        }
        else
        {
            return false;
        }

    }

    public synchronized void releaseLock(int id)
    {
        /**
         * Any thread can call this, releasing the lock. of course, the lock will only be 
         * released if the thread calling it actually owns the lock.
         */

        if(id == this.lock)
        {
            this.lock = 0;
        }
        else
        {
            //do nothing
        }
    }

    public synchronized void publish(String toSend)
    {
        /**
         * When a thread in control of the lock wants to publish to all other threads, it
         * invokes this method, which then calls another synchronised method on each thread
         * in the list, telling it to write to it's client with the new data. 
         */

        for(int i = 0; i<this.SocketList.size(); i  )
        {
            if(i != this.lock)
            {
                this.SocketList.get(i).sendData(toSend);
            }
        }
    }


}



class ClientServiceThread extends Thread{

    Socket mySocket;
    int id;
    boolean hasControl = false;

    public ClientServiceThread(Socket mySocket, int id)
    {
        /**
         * this constructor gives it the ID and the socket for communication, it will
         * then be run
         */
        this.mySocket = mySocket;
        this.id = id;

    }

    @Override
    public void run()
    {
        //listen, it will be either a request, or some data
        //based on whether the client is the one in control or not (hasControl)
        try{
            //create buffered reader

            if(!this.hasControl)
            {
                //it has control, so wait for the lines
            }
            else
            {
                //read in one line and then call acquire lock because we know
                //that it has sent a request for control
                // how do i access the original class for acquireLock();?


            }


        }catch(IOException e)
        {
            System.out.println("Problem reading from the socket");
        }

    }

    public synchronized void sendData(String toSend)
    {
        //create writer and send to my client, saying "true" or some other message
        //the client will recognise as the go-ahead to edit the data. 
    }


}
  

Ответ №1:

Вероятно, вам лучше использовать что-то вроде MINA вместо того, чтобы создавать свои собственные. Поместите клиентские команды в параллельную очередь и обрабатывайте их по одной за раз, чтобы вам не приходилось беспокоиться о синхронизации.

В качестве альтернативы, рассмотрите возможность использования интерфейса RESTful вместо сокетов (или, если на то пошло, чего-то другого, кроме апплета, например, Ext JS).

Комментарии:

1. Привет, спасибо за ответ, я уверен, что эти реализации больше подходят, но я забыл упомянуть, что это для университетского проекта, который, к сожалению, должен включать swing и сокеты:(

2. О, хорошо, я новичок в этом, первый в истории вопрос: p

3. В любом случае, мой комментарий остается в силе: команды должны генерироваться клиентами и помещаться в параллельную очередь, которая затем обрабатывается потоком команд.