Java 使用PipedOutputStream时,线程争用条件刚刚挂起

Java 使用PipedOutputStream时,线程争用条件刚刚挂起,java,thread-safety,java.util.concurrent,java-threads,Java,Thread Safety,Java.util.concurrent,Java Threads,我使用管道输出流将OutputStream转换为InputStream,因为AWS java sdk不允许使用OutputStreams在S3上放置对象 我正在使用下面的代码,但是,它会间歇性地挂起。此代码位于web应用程序中。目前应用程序上没有加载…我只是在我的个人电脑上尝试 ByteArrayOutputStream os = new ByteArrayOutputStream(); PipedInputStream inpipe = new PipedInputStream(); fina

我使用管道输出流将
OutputStream
转换为
InputStream
,因为AWS java sdk不允许使用
OutputStreams
在S3上放置对象

我正在使用下面的代码,但是,它会间歇性地挂起。此代码位于web应用程序中。目前应用程序上没有加载…我只是在我的个人电脑上尝试

ByteArrayOutputStream os = new ByteArrayOutputStream();
PipedInputStream inpipe = new PipedInputStream();
final PipedOutputStream out = new PipedOutputStream(inpipe);
try {
   String xmpXml = "<dc:description>somedesc</dc:description>"
   JpegXmpRewriter rewriter = new JpegXmpRewriter();
   rewriter.updateXmpXml(isNew1,os, xmpXml); 
      new Thread(new Runnable() {
          public void run () {
              try {
                  // write the original OutputStream to the PipedOutputStream
                  println "starting writeto"
                  os.writeTo(out);
                  out.close();
                  println "ending writeto"
              } catch (IOException e) {
                  System.out.println("Some exception)
              }
          }
      }).start();
      ObjectMetadata metadata1 = new ObjectMetadata();
      metadata1.setContentLength(os.size());
      client.putObject(new PutObjectRequest("test-bucket", "167_sample.jpg", inpipe, metadata1));
    }
 catch (Exception e) { 
      System.out.println("Some exception")
 }
 finally {
    isNew1.close()
    os.close()
 }
ByteArrayOutputStream os=newbytearrayoutputstream();
PipedInputStream inpipe=新的PipedInputStream();
最终管道输出流=新管道输出流(输入管道);
试一试{
字符串xmpXml=“somedesc”
JpegXmpRewriter rewriter=新的JpegXmpRewriter();
updateXmpXml(isNew1,os,xmpXml);
新线程(newrunnable()){
公开作废运行(){
试一试{
//将原始输出流写入PipedOutputStream
println“开始写入”
操作系统写入(输出);
out.close();
println“结束写入”
}捕获(IOE异常){
System.out.println(“某些异常)
}
}
}).start();
ObjectMetadata metadata1=新的ObjectMetadata();
metadata1.setContentLength(os.size());
putObject(新的PutObjectRequest(“testbucket”,“167_sample.jpg”,inpipe,metadata1));
}
捕获(例外e){
System.out.println(“某些异常”)
}
最后{
isNew1.close()
操作系统关闭()
}

与其麻烦于启动另一个线程、实例化两个并发类,然后在线程之间传递数据的复杂性,所有这些都只是为了解决提供的JDK API中的一个小限制,您只需创建一个简单的
ByteArrayOutputStream专门化即可:

class BetterByteArrayOutputStream extends ByteArrayOutputStream {
    public ByteArrayInputStream toInputStream() {
        return new ByteArrayInputStream(buf, 0, count);
    }
}

这会将其转换为无需复制的输入流。

为了便于参考,这里讨论了这种技术(避免再次复制BAO的内容):是否有线程转储(kill-QUIT)?我知道这个解决方案。这就是我的snipper的来源,这正是我在我的问题中所做的,不是吗?您对BAO的使用是否会击败管道流的优势?事实上,您应该做的是调用
rewriter.updateXmpXml(isNew1,out,xmpXml)
来自您创建的线程。请注意,我写了
而不是
os
。我同意@Thilo的观点,即收集到BAOS中具有已知大小的优势,并且在上传开始之前知道成功与否。但是,一旦您在RAM中有了数据,就再也没有必要参与启动另一个线程的复杂性了d和从一个线程到另一个线程传递数据,只是为了解决一个愚蠢的API限制。这看起来很有希望。你能再解释一下吗?返回语句中的
buf
是什么?在
rewriter.updateXmpXml(isNew1,os,xmpXml);
?。
client.putObject(新PutObjectRequest(“test bucket”,“167_sample.jpg”)之后我该如何调用它,os.toInputStream(),metadata1))这似乎起作用了。这对大文件有效吗?这是将所有数据都保存在内存中吗?考虑到您最初的解决方案已经将所有数据都保存在RAM中,这是一个奇怪的问题。这只是重复使用相同的数据。对。我忘了。使用管道流,给人一种错觉,我不是。如果这对大文件不起作用,那么我将回到pipedstream,但按照您在评论中的建议删除bao。出于某种原因,这对我不起作用。我将发布另一个关于它的问题。谢谢