我正在开发一个简单的项目:服务器在读取文件的线程内执行从属(ReaderF类),然后提取其内容并将其保存在服务器本身内。然后,服务器需要执行池以在连接时将内容发送到客户端。我开始编写ReaderF来提取内容。问题:它从不编辑他应该存储内容的String变量。这是我做的:
public class Serveur {
private ServerSocket serverSocket;
private Socket socket;
public String res=null; //This is what my thread is supposed to be editing
ExecutorService pool = null;
public static final int port = 33333;
Serveur(int port, int size){
try {
pool = Executors.newFixedThreadPool(5);
serverSocket = new ServerSocket(port, size);
} catch (IOException ex) {
Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE, null, ex);
}
}
void manage () throws IOException {
while(true) {
ReaderF S = null;
try {
S = new ReaderF(serverSocket.accept(), this);
} catch (IOException e) {
e.printStackTrace();
}
Thread t=new Thread(S);
t.start();
}
}
这是读取和编辑res变量的从属设备。
public class ReaderF implements Runnable {
private final Socket socket;
private Serveur serverMaitre;
ReaderF(Socket socket, Serveur serverMaitre) {
this.socket = socket;
this.serverMaitre = serverMaitre;
}
public void run() {
String fileName = "/home/abdou/1.txt";
FileReader fileReader = null;
Writer output =null;
try {
fileReader = new FileReader(fileName);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (BufferedReader bufferedReader = new BufferedReader(fileReader)) {
output = new OutputStreamWriter(socket.getOutputStream(), "8859_1");
String line;
String res="";
while((line = bufferedReader.readLine()) != null) {
res+=line+"\n";
}
serverMaitre.res=res; // This is where i tell him to edit res inside the server
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
当我执行此主要内容时,我在屏幕上看不到任何内容。我知道这是因为服务器停留在while循环中。
public class Main{
public static void main(String[] args) throws IOException {
Serveur serveur = new Serveur(Serveur.port, 1);
serveur.manage();
System.out.println("The res variable content is"+serveur.res);
}}
我怎么能摆脱它呢。我的线程是否真的改变了res变量?谢谢
答案 0 :(得分:0)
当多个线程使用相同的变量时,允许它们处理变量的本地副本(在其堆栈中)而不是原始变量(在堆中)。这意味着一个线程可能看不到另一个线程所做的变量的更改(他没有'刷新'其本地数据),或者另一个线程没有'发布'(技术术语:刷新)更新的值。因此,当您的ReaderF为'res'赋值时,主线程(正在检查它)可能不会注意到这一点。解决方案:创建变量volatile
:
public volatile String res=null;
这会强制ReaderF在分配后刷新更新的值,并在读取时刷新主线程。
但是你可能在这里有另一个问题,因为你有多个线程可能都在写'res'变量(取决于你的套接字有多活跃)。您可以在这里获得“丢失的更新”或其他“竞争条件”。所以也许你甚至需要一个synchronized
。但是这里解释多线程太过分了。请谷歌了解一下。不幸的是,多线程并不是一件轻而易举的事情,你不能只是按照自己的意愿制作新的线程,并希望一切顺利。在大多数情况下,添加volatile是而不是解决方案。这可能只是你想在这里做的事情。