从 Java 中的两个线程访问共享变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4440436/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Accessing shared variables from two threads in Java
提问by CodePredator
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?
我正在用 Java 构建一个应用程序,它需要从两个类的实例访问一个 Hashtable,并且都扩展线程。我已经在两个类之一中声明了 Hashtable。当我尝试从其中一个类访问 Hashtable 内容时,我总是得到 null。另一个类能够毫无问题地访问内容。我以为这是并发控制的问题。由于这些是不同类的线程,我们不能使用同步方法。有没有办法让两个类的线程都可以访问 Hashtable?
Here are the some parts of the code of my application This is the class which stores the HashMap:
这是我的应用程序代码的某些部分 这是存储 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
访问“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.
这个类也有 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");
}
}
} }
} }
回答by Boris Pavlovi?
It's possible. Take a look at Sharing data safely between two threads.
这是可能的。看看在两个线程之间安全地共享数据。
回答by dacwe
Okey, I couldn't use your code because I don't understand, what I did see was that you want something like this:
好吧,我无法使用你的代码,因为我不明白,我确实看到你想要这样的东西:
- Create a empty
JFrame
with aJTabbedPane
and start a thread that connects to aSocket
- When input comes on the socket, create a
ChatPanel
(~JTextArea
) and add it to one of the tabs - Add the
ChatPanel
to aMap
that handles the messages from "from
" - Pass the message to the newly created
ChatPanel
JFrame
用 a创建一个空的JTabbedPane
并启动一个连接到 a 的线程Socket
- 当输入出现在套接字上时,创建一个
ChatPanel
(~JTextArea
) 并将其添加到选项卡之一 - 添加
ChatPanel
到Map
处理来自“from
”的消息的 - 将消息传递给新创建的
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
.
如果您想对此进行测试,请先启动TestChatServer
(下面的代码),然后是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);
}
}
}
}