我是Java的初学者,也许我想做的事情在Java中真的不起作用,但我希望有人可以帮助我。
我想做什么: 我有两个Threads,一个Thread创建了几个相同的Object并使用它,最后我想通过Pipe将这些对象发送到另一个Thread,我希望将它保存在File中。
我知道,我可以使用Vector,所以其他Thread可以从那里获取Objects,但是在下一步我想在Sever和Client中分离这个项目,所以我需要这些Pipes,我可以发送Objects。我已经在互联网上搜索了正确的答案,但我确实找到了我需要的东西。这是一个想法,我认为可以工作,但它没有真正的:
MainThread:
public class ControlerThread {
public static void main(String[] args) {
PipedReader pr = new PipedReader();
PipedWriter pw = new PipedWriter();
PipedOutputStream pos = null;
PipedInputStream pis = null;
ObjectOutputStream oos =null;
ObjectInputStream ois = null;
try
{
pw.connect(pr);
pis = new PipedInputStream();
pos = new PipedOutputStream(pis);
oos = new ObjectOutputStream(pos);
ois = new ObjectInputStream(pis);
}catch(IOException ioe)
{
}
ModelThread mt = new ModelThread(ois,pr);
ViewThread vt = new ViewThread(oos,pw);
vt.start();
mt.start();
}
}
我创建对象的ViewThread ...
public class ViewThread extends Thread{
PipedWriter pw;
BufferedWriter bw;
ObjectOutputStream oos;
public ViewThread(ObjectOutputStream oos,PipedWriter pwr )
{
this.oos = oos;
this.pw = pwr;
bw = new BufferedWriter(pw);
}
public void run()
{
int iEingabe = 0;
Menu mu = new Menu();
do {
iEingabe = 0;
System.out.println("\t eine neue Person aufnehmen: > 1");
System.out.println("\t \t Records auflisten: > 2");
System.out.println(" Records in eine Datei sichern: > 3");
System.out.println(" Records aus einer Datei laden: > 4");
System.out.println(" in-memory Records sortieren: > 5");
System.out.println("\t\t Datei löschen: > 6");
System.out.println("\t das Programm verlassen: > 7");
System.out.print("\nIhre Eingabe: ");
iEingabe = Eingabe.readInt();
switch (iEingabe) {
case 1: mu.addContact(); break;
case 2: mu.outputMatrix(); break;
case 3: try{
bw.write("3");
bw.write("\n");
bw.flush();
Kontakt k = new Kontakt();
oos.writeObject(k);
oos.flush();
}catch(IOException ioe)
{
ioe.printStackTrace();
}; break;
case 4: break;
case 5: mu.kontakteSortieren();break;
case 6: /*mu.deleteFile()*/; break;
case 7: System.out.println("Programm wird beended!"); break;
}
} while (iEingabe != 7);
}
}
这是后来应该获取Object的线程:
package Thread;
import java.io.*;
public class ModelThread extends Thread{
private PipedReader pr = null;
private BufferedReader br = null;
//private String datei = "test.csv";
//private FileOutputStream fos;
//private ObjectOutputStream oos = null;
// private FileInputStream fis;
private ObjectInputStream ois = null;
public ModelThread(ObjectInputStream ois,PipedReader pr)
{
this.pr = pr;
br = new BufferedReader(pr);
this.ois = ois;
}
public void run()
{
try
{
if(br.readLine().equals("3"))
{
Kontakt k = (Kontakt) ois.readObject();
System.out.println(k.name);
}
}catch(IOException e)
{
}catch(ClassNotFoundException ce)
{
}
}
}
但如果我像上面那样做,我会得到一个IOException“Read end dead”。我希望每个人都明白我想做什么,可以帮助我。
例外:
java.io.IOException: Read end dead
at java.io.PipedInputStream.checkStateForReceive(Unknown Source)
at java.io.PipedInputStream.receive(Unknown Source)
at java.io.PipedOutputStream.write(Unknown Source)
at java.io.ObjectOutputStream$BlockDataOutputStream.writeBlockHeader(Unknown Source)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(Unknown Source)
at java.io.ObjectOutputStream$BlockDataOutputStream.flush(Unknown Source)
at java.io.ObjectOutputStream.flush(Unknown Source)
at Thread.ViewThread.run(ViewThread.java:57)
感谢!!!
答案 0 :(得分:3)
在这个ModelThread处理了命令他听的数据之前,你的ViewThread确实有一个竞争条件将对象数据发送到ModelThread。
java.io.IOException: Read end dead
表示您的PipedInputStream
实际上还没准备好开展工作。查看源代码,当管道输入流具有"没有人"时,抛出此特定异常。 (实际上没有线程)从中读取。所以,让我们看看您的代码何时开始从PipedInputStream中读取。
看到你的代码(我可以建议你重命名你的变量吗?从陌生人的角度来看,很难看出为什么每个班级都需要这么多的流,而且当他们有名字的时候所有的读者都互相管道比如pis
,ois
,pr
...),我们拥有2个线程共享"命令" channel(读者/作者和"对象"(或" data")通道,其中交换序列化数据。
程序启动后,当用户输入" 3" (在System.in?中)编写器线程:写" 3"按下命令管道,然后将对象写入对象管道(这是你崩溃的地方) 并且当其他线程"看到" 3 在命令管道上,然后它开始从数据管道监听(我们知道没有发生,因为我们崩溃了)。
为什么在ViewThread开始写入之前,ModelThread没有从数据管道开始监听?好吧,因为你的程序需要......
最糟糕的情况:你甚至无法确定你的ModelThread是否真正开始了(当然,你可以期待它有,但你无法知道)。如果您还不知道它已经启动了,您肯定无法知道它是否侦听命令管道,更不用说从它读取它并且它已经继续从对象管道读取。
嗯.. 实际上是:如果您对对象管道有异常,我们可以知道在您的程序的这个实例中,命令管道工作,意味着两个线程实际上都已启动,并且ModelThread至少输入了命令管道的read方法。但是你不知道下次启动程序时会出现这种情况。
无论如何,在这种情况下,命令管道工作,你发送命令" 3"下。接下来是什么。
你的ModelThread将最终拿起命令" 3"并且一段时间之后,即使只是一小段时间,也会开始从对象管道中读取......但是又一次:你不知道这究竟会发生什么时候。在ViewThread开始写下对象管道之前或之后?如果它之前:你的程序应该工作。如果没有,你得到你提到的例外。
嗯,总有一点未知,但全球
第4步至关重要。如果你有多个CPU,那么你的计算机是否过载,你无法知道调度程序将选择做什么以及它相对于读取时间的速度有多快。
那就是我们发明同步工具的原因。在您当前的设计中,您需要同步(CountDownLatch
?)以确保您的阅读方面至少在您的写作方面已经开始。但从长远来看,这可能并不理想......
看到你的目标是一个客户端/服务器应用程序,这不会做到这一点:同步工具(锁,信号量,任何类型的信号)在一个进程(或最多一台计算机)内工作,但你赢了&# 39;能够在客户端/服务器架构上使用它们。
另外:您可能在这个架构中没有管道,您将拥有简单的InputStream / Output流。因此,我不确定您是否通过这种方式设计使您的设计变得更简单。
这实际上是一种机会(某种形式):网络通信涉及套接字。套接字是双向通信支持:您可以读取和写入套接字。所以也许你可以修改你的协议,以便:
确认阶段是您的同步"工具。当你收到它时,它意味着另一方已经准备好了#34;。
它的价值:你的"协议"让我想起好老的FTP ......你有一个"命令频道" (客户端要求服务器列出目录,请求文件等),并且当必须进行传输时,客户端&然后,服务器为此数据交换打开第二个连接(数据连接)。
不是说你应该这样做,但它可能会激励你。