简体   繁体   中英

Accessing shared variables from two threads in Java

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");

       }
   }

} }

It's possible. Take a look at Sharing data safely between two threads .

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

屏幕截图

  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);
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM