Java开发中如何访问另一个线程中的BufferedWriter等变量?
问题原因
你无法访问BufferedWriter的核心原因是:bufferedWriter被定义为线程run方法内的局部变量,作用域仅限run方法内部,外部的动作监听器自然无法访问。同时你原有代码中试图在构造方法末尾直接引用bufferedWriter、outputStreamWriter的写法也完全不可行:这两个变量属于线程内部局部变量,外部作用域不可见,且线程是异步执行的,构造方法执行到末尾时,线程大概率还没完成Socket连接和Writer初始化,就算能访问也大概率拿到空对象。
修复步骤
- 将需要跨模块访问的IO对象提升为类的成员变量,添加
volatile关键字保证多线程下的变量可见性 - 在线程完成IO对象初始化后给成员变量赋值
- 修复原有逻辑漏洞:
- 原有读取逻辑重复调用
bufferedReader.readLine(),会导致一半消息被吞 - 不能在非Swing事件调度线程直接操作
JTextArea等Swing组件,需用SwingUtilities.invokeLater包裹更新逻辑 - 原有循环逻辑无法实现持续收发消息,替换为持续监听服务端消息的逻辑
- 原有读取逻辑重复调用
- 发送消息前先判断
BufferedWriter是否初始化完成,避免空指针异常
修改后的完整代码
package com.mpemessenger; import javax.swing.*; import java.awt.event.ActionEvent; import java.io.*; import java.net.Socket; public class GUIClient extends JFrame { private JTextField messageField; private JButton sendButton; private JTextArea messageArea; private JScrollPane scroll; private JPanel All; // 提升为类成员变量,加volatile保证多线程可见性 private volatile BufferedWriter bufferedWriter; private Socket socket; public GUIClient() { add(All); setTitle("MPE Messenger"); setSize(400, 500); scroll.setAutoscrolls(true); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); messageArea.setEditable(false); All.getRootPane().setDefaultButton(sendButton); // 启动Socket连接监听线程 Thread connectThread = new Thread(() -> { try { socket = new Socket("localhost", 6969); // 初始化IO流 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 发送上线消息,写完要flush才能发出去 bufferedWriter.write("Connected!!!"); bufferedWriter.newLine(); bufferedWriter.flush(); // 持续监听服务端消息 String msg; while ((msg = bufferedReader.readLine()) != null) { final String serverMsg = msg; // Swing组件更新必须放到事件调度线程执行 SwingUtilities.invokeLater(() -> messageArea.append("Server:" + serverMsg + "\n")); } } catch (IOException e) { e.printStackTrace(); } }); connectThread.start(); // 发送按钮监听 sendButton.addActionListener(e -> { String content = messageField.getText().trim(); if (content.isEmpty() || bufferedWriter == null) { return; } try { bufferedWriter.write(content); bufferedWriter.newLine(); bufferedWriter.flush(); messageArea.append("我:" + content + "\n"); messageField.setText(""); } catch (IOException ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(this, "消息发送失败:" + ex.getMessage()); } }); } public static void main(String[] args) { // Swing界面启动必须放到事件调度线程 SwingUtilities.invokeLater(() -> new GUIClient().setVisible(true)); } }
内容的提问来源于stack exchange,提问作者Monte Scott Barber
相关产品推荐
相关产品推荐

