Java中两个线程访问共享变量

发布于 2024-10-07 12:42:37 字数 3304 浏览 0 评论 0原文

我正在用 Java 构建一个应用程序,它需要从两个类的实例访问哈希表,并且两个类都扩展线程。我已在两个类之一中声明了哈希表。当我尝试从其中一个类访问哈希表内容时,我总是得到 null。另一个类能够毫无问题地访问内容。我以为这是并发控制的问题。由于这些是不同类的线程,我们不能使用同步方法。有没有办法使哈希表可以从两个类的线程访问?

这是我的应用程序代码的一些部分 这是存储 HashMap 的类:

public class DataStore {
public Map ChatWindows ;
public DataStore()
{
    ChatWindows = new ConcurrentHashMap();
}
public synchronized void putWindow(String with,ChatWindow t)
{
    ChatWindows.put(with,t);
    notifyAll();
}
public synchronized ChatWindow getWindow(String with)
{
    notifyAll();
    return (ChatWindow)ChatWindows.get(with);
}
public synchronized void ChatWindowOpen(chatClient cc,String with,String msg)
    {
       //    chatWith = with;
        ChatWindow t;
        System.out.println(with);
            t = getWindow(with);
           if(t == null)
           {
               t = new ChatWindow(cc,with,msg);
         //      th = new Thread(t);
               putWindow(with, t);
         //      th.start();
           }
           else
           {
              t.setVisible(true);

            }
}
}

访问“ChatWindows”HashMap 的两个类

public class chatClient extends javax.swing.JFrame implements 

Runnable,ListSelectionListener,MouseListener,WindowListener{

  static String LoginName,chatWith,msgToChatWindow;
    Thread listThread=null,th,chatListen;
static  Socket soc;
static  DataOutputStream dout,dout1;
static  DataInputStream din,din1;
        DefaultListModel listModel;

        ChatWindow t;

    public DataStore ds;
/** Creates new form chatClient */
public chatClient(Login l,DataStore ds) {
    listModel = new DefaultListModel();
    initComponents();
    clientList.addListSelectionListener(this);

     clientList.addMouseListener(this);
     addWindowListener(this);
      this.LoginName=l.loginName;

        soc = l.soc2;
        din = l.din2;
        dout = l.dout2;
        dout1 = l.dout1;
        din1 = l.din1;
        super.setTitle(LoginName);

        listThread = new Thread(this);
        listThread.start();
        this.ds = ds;

}
.
.
.
.
public void mouseClicked(MouseEvent e)
{
    chatWith = (String)clientList.getSelectedValue();
    ds.ChatWindowOpen(this,chatWith,"");
}

该类也有 run() 方法,但不使用 HashMap。该类能够正确访问“ChatWindows”。“ChatListenThread”类无法正确访问 HashMap 的内容。

public class ChatListenThread implements Runnable{

DataOutputStream dout1;
DataInputStream din1;
public static chatClient cc;
public static ChatWindow t;
public DataStore ds;
    public ChatListenThread(Login l,DataStore ds)
    {
        din1 = l.din1;
        dout1= l.dout1;
        this.ds = ds;
    }
.
.
.
.
public void run(){
   while(true)
   {
       try{
                    String msgFromServer=new String();
                    msgFromServer = din1.readUTF();
                    StringTokenizer st=new StringTokenizer(msgFromServer);
        String msgFrom=st.nextToken();
        String MsgType=st.nextToken();
                    String msg = "";
                   while(st.hasMoreTokens())
        {
            msg=msg+" " +st.nextToken();
        }

                    ds.ChatWindowOpen(cc,msgFrom,msg);                       

       }
       catch(IOException e)
       {
            System.out.println("Read failed");

       }
   }

} }

I'm building an application in Java which requires a Hashtable to be accessed from instances of two classes and both extend threads. I have declared the Hashtable in one of the two classes. I always get null when i try to access the Hashtable contents from one of the classes. The other class is able to access the contents without any problem. I thought this was a problem of concurrency control. Since these are threads of different classes we cannot use synchronized methods. Is there a way to make the Hashtable accessible from threads of both the classes?

Here are the some parts of the code of my application
This is the class which stores the HashMap:

public class DataStore {
public Map ChatWindows ;
public DataStore()
{
    ChatWindows = new ConcurrentHashMap();
}
public synchronized void putWindow(String with,ChatWindow t)
{
    ChatWindows.put(with,t);
    notifyAll();
}
public synchronized ChatWindow getWindow(String with)
{
    notifyAll();
    return (ChatWindow)ChatWindows.get(with);
}
public synchronized void ChatWindowOpen(chatClient cc,String with,String msg)
    {
       //    chatWith = with;
        ChatWindow t;
        System.out.println(with);
            t = getWindow(with);
           if(t == null)
           {
               t = new ChatWindow(cc,with,msg);
         //      th = new Thread(t);
               putWindow(with, t);
         //      th.start();
           }
           else
           {
              t.setVisible(true);

            }
}
}

Two classes which access 'ChatWindows' HashMap

public class chatClient extends javax.swing.JFrame implements 

Runnable,ListSelectionListener,MouseListener,WindowListener{

  static String LoginName,chatWith,msgToChatWindow;
    Thread listThread=null,th,chatListen;
static  Socket soc;
static  DataOutputStream dout,dout1;
static  DataInputStream din,din1;
        DefaultListModel listModel;

        ChatWindow t;

    public DataStore ds;
/** Creates new form chatClient */
public chatClient(Login l,DataStore ds) {
    listModel = new DefaultListModel();
    initComponents();
    clientList.addListSelectionListener(this);

     clientList.addMouseListener(this);
     addWindowListener(this);
      this.LoginName=l.loginName;

        soc = l.soc2;
        din = l.din2;
        dout = l.dout2;
        dout1 = l.dout1;
        din1 = l.din1;
        super.setTitle(LoginName);

        listThread = new Thread(this);
        listThread.start();
        this.ds = ds;

}
.
.
.
.
public void mouseClicked(MouseEvent e)
{
    chatWith = (String)clientList.getSelectedValue();
    ds.ChatWindowOpen(this,chatWith,"");
}

This class has run() method too, but that doesn't use the HashMap. This class is able to access the 'ChatWindows' properly.'ChatListenThread' class is not able to access the contents of HashMap properly.

public class ChatListenThread implements Runnable{

DataOutputStream dout1;
DataInputStream din1;
public static chatClient cc;
public static ChatWindow t;
public DataStore ds;
    public ChatListenThread(Login l,DataStore ds)
    {
        din1 = l.din1;
        dout1= l.dout1;
        this.ds = ds;
    }
.
.
.
.
public void run(){
   while(true)
   {
       try{
                    String msgFromServer=new String();
                    msgFromServer = din1.readUTF();
                    StringTokenizer st=new StringTokenizer(msgFromServer);
        String msgFrom=st.nextToken();
        String MsgType=st.nextToken();
                    String msg = "";
                   while(st.hasMoreTokens())
        {
            msg=msg+" " +st.nextToken();
        }

                    ds.ChatWindowOpen(cc,msgFrom,msg);                       

       }
       catch(IOException e)
       {
            System.out.println("Read failed");

       }
   }

}
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

瞄了个咪的 2024-10-14 12:42:37

好吧,我无法使用你的代码,因为我不明白,我看到的是你想要这样的东西:

屏幕截图

  1. 使用 JTabbedPane 创建一个空的 JFrame 并启动一个连接到 Socket 的线程。
  2. 当套接字上有输入时,创建一个ChatPanel (~JTextArea) 并将其添加到选项卡之一
  3. ChatPanel 添加到处理来自“from”的消息
  4. 将消息传递到新创建的 ChatPanel

所以我这样做了,并发布了下面的代码! 希望您能使用它!

如果您想测试一下,请首先启动 TestChatServer(代码如下),然后启动 ChatSupervisor .

这是客户端的代码

public class ChatSupervisor extends JFrame implements Runnable {

    JTabbedPane tabs = new JTabbedPane();
    Map<String, ChatPanel> chats = new ConcurrentHashMap<String, ChatPanel>();

    public ChatSupervisor() {
        super("Test Chat");
        add(tabs, BorderLayout.CENTER);

        new Thread(this).start();
    }

    public void run() {
        Socket sock = null;
        try {
            sock = new Socket("localhost", 32134);

            Scanner s = new Scanner(sock.getInputStream());
            while (true) {

                String from = s.next();
                String type = s.next();
                String message = s.nextLine();

                getChat(from).incomingMessage(type, message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sock != null) try { sock.close(); } catch (IOException e) {}
        }
    }

    public ChatPanel getChat(String from) {
        if (!chats.containsKey(from))
            chats.put(from, new ChatPanel(from));

        return chats.get(from);
    }

    public static void main(String[] args) {
        ChatSupervisor cs = new ChatSupervisor();
        cs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cs.setSize(400, 300);
        cs.setVisible(true);
    }

    class ChatPanel extends JTextArea {
        public ChatPanel(final String from) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    tabs.addTab(from, ChatPanel.this);
                }
            });
        }
        public void incomingMessage(final String type, final String message) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    append("[" + type + "]" + message);
                    append("\n");
                }
            });
        }
    }
}

这是测试服务器的代码:

public class TestChatServer {
    public static void main(String[] args) throws Exception {
        Socket s = new ServerSocket(32134).accept();
        System.out.println("connected");
        PrintWriter p = new PrintWriter(s.getOutputStream());
        while (true) {

            p.println("hello info Hello World!");
            p.flush();
            Thread.sleep(1000);

            for (int i = 0; i < 10; i++) {
                p.println("test" + i + " warn Testing for testing " + i);
                p.flush();
                Thread.sleep(100);
            }
        }
    }
}

Okey, I couldn't use your code because I don't understand, what I did see was that you want something like this:

Screen shot

  1. Create a empty JFrame with a JTabbedPane and start a thread that connects to a Socket
  2. When input comes on the socket, create a ChatPanel (~JTextArea) and add it to one of the tabs
  3. Add the ChatPanel to a Map that handles the messages from "from"
  4. Pass the message to the newly created ChatPanel

So I did that and I'm posting the code below! Hope that you can use it!

If you like to test this, first start the TestChatServer (code below) and then the ChatSupervisor.

This is the code for the client

public class ChatSupervisor extends JFrame implements Runnable {

    JTabbedPane tabs = new JTabbedPane();
    Map<String, ChatPanel> chats = new ConcurrentHashMap<String, ChatPanel>();

    public ChatSupervisor() {
        super("Test Chat");
        add(tabs, BorderLayout.CENTER);

        new Thread(this).start();
    }

    public void run() {
        Socket sock = null;
        try {
            sock = new Socket("localhost", 32134);

            Scanner s = new Scanner(sock.getInputStream());
            while (true) {

                String from = s.next();
                String type = s.next();
                String message = s.nextLine();

                getChat(from).incomingMessage(type, message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (sock != null) try { sock.close(); } catch (IOException e) {}
        }
    }

    public ChatPanel getChat(String from) {
        if (!chats.containsKey(from))
            chats.put(from, new ChatPanel(from));

        return chats.get(from);
    }

    public static void main(String[] args) {
        ChatSupervisor cs = new ChatSupervisor();
        cs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cs.setSize(400, 300);
        cs.setVisible(true);
    }

    class ChatPanel extends JTextArea {
        public ChatPanel(final String from) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    tabs.addTab(from, ChatPanel.this);
                }
            });
        }
        public void incomingMessage(final String type, final String message) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    append("[" + type + "]" + message);
                    append("\n");
                }
            });
        }
    }
}

This is the code for the test server:

public class TestChatServer {
    public static void main(String[] args) throws Exception {
        Socket s = new ServerSocket(32134).accept();
        System.out.println("connected");
        PrintWriter p = new PrintWriter(s.getOutputStream());
        while (true) {

            p.println("hello info Hello World!");
            p.flush();
            Thread.sleep(1000);

            for (int i = 0; i < 10; i++) {
                p.println("test" + i + " warn Testing for testing " + i);
                p.flush();
                Thread.sleep(100);
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文