【问题标题】:Synchronizing threads in list同步列表中的线程
【发布时间】:2014-02-14 20:11:20
【问题描述】:

我知道有很多关于线程同步的问题,但没有人给我解释如何在我的实现中使用它。所以我有一个等待客户端连接的服务器,因为在连接时为每个连接的客户端创建一个线程,从每个客户端发送的每条消息都将显示在服务器中,并带有 clientIP>>,然后每个客户端将从服务器检索此消息,以便每个客户端都有相同的消息。类似于 mIRC 可能会添加..

好吧,问题解决了:

我在链表中​​保存每个连接的客户端的会话实例。

我的会话类很简单:

public class Session extends Thread{
    private Socket soc;

    public BufferedReader in;
    public PrintWriter out;

    public Session(Socket in_client){
        //soc = new Socket();
        soc = in_client;
        this.start();
    }

    @Override
    public void run() {

        try{

            in = new BufferedReader(new InputStreamReader(soc.getInputStream()));
            out = new PrintWriter(soc.getOutputStream(), true);

            String inputLine;

            while(true){
                if((inputLine = in.readLine()) != null){
                    textArea.append("Client IP["+soc.getInetAddress()+"]: " + inputLine+"\n");

                    for(Session s:dstruct)
                        s.out.println(s.soc.getInetAddress()+">"+inputLine);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }catch(IOException e ){
            try {
                in.close();
                out.close();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }}
    }

}

在服务器线程运行方法中,我创建会话并通过以下方式将它们推送到数据结构链表:

while(true){        
    if((clientSocket = serverSocket.accept())!=null){
        dstruct.push(new Session(clientSocket));
    }

现在我将如何使这些线程同步?我已经阅读了许多不同的建议,例如 调用 synchronized(...) 或在方法声明中进行了同步,还阅读了通知,但在通知线程时无法理解这会完成什么, 在这种情况下我会把它放在哪里? 我有一个服务器线程检查客户端将它们连接到由 Thread 扩展的会话。主线程应该同步子线程还是应该有一些同步方法来同步它们?

【问题讨论】:

  • 您显示了将会话添加到列表的位置,但是您从哪里开始线程?
  • 你一定是指main方法中启动的主线程,
  • Server类有一个main方法启动线程然后跳转到run方法希望澄清一下,子线程是在session的构造函数中启动的。
  • 请正确格式化您的帖子(看看代码是如何格式化的),这将使您有更好的机会获得有意义的答案

标签: java multithreading sockets client-server


【解决方案1】:

如果我正确理解了这个问题,您想确保当Sessiondstruct 读取时,它可以看到Server 已放入列表中的所有Sessions?最简单的做法是使用来自java.util.concurrent 的类,例如ConcurrentLinkedQueueConcurrentLinkedDeque

尝试将dstruct 定义为ConcurrentLinkedQueue<Session>

【讨论】:

  • 嗯,我不知道那会完成什么?我基本上需要同步线程,这样可以吗?
  • 我一定没有正确理解这个问题。正在同步的线程是什么意思?
  • 我知道同步是什么,但如果dstruct 是一个线程安全的集合,那你为什么需要任何额外的同步呢?
  • 好的,这是一个学校作业,其中一个要求是拥有同步线程,所以这就是我试图找出的,现在我不确定所以我要同时使用并发列表和声明从列表中推送和删除的同步方法,您说并发列表足够了吗?
【解决方案2】:

同步线程的目标是确保对线程共享的任何数据的操作原子地完成,以确保线程所看到的数据的一致性。在同步块或方法中进行同步的效果是,进入该块的第一个线程将在与同步对象关联的监视器上获得锁。随后通过在同一对象上输入相同或另一个同步块/方法来请求该锁的所有其他线程将不得不等到锁被释放,每当初始线程退出同步块时就会发生这种情况。

在您的情况下,共享数据是 LinkedList dstruct,这是您在所有操作中都需要原子性的对象。因此,在您展示的代码中,您需要在两个地方进行同步:

在Session的run()方法中,需要同步整个for循环:

synchronized(dstruct) {
  for (Session s: dstruct)
    s.out.println(s.soc.getInetAddress()+">"+inputLine);
  }
}

在Server的run()方法中,围绕push()操作:

if ((clientSocket = serverSocket.accept()) != null) {
  synchronized(dstruct) {
    dstruct.push(new Session(clientSocket));
  }
}

通过谷歌搜索“java线程同步”,你会发现很多关于这个主题的材料和学习资源,比如this one。我很确定你会在那里找到一些能让你明白的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-30
    • 1970-01-01
    • 2021-12-05
    相关资源
    最近更新 更多