2012-02-28 27 views
8

Tôi đã nhìn thấy hai câu trả lời trên SO cho rằng các lớp học PipedInputStreamPipedOutputStream do Java cung cấp là thiếu sót. Nhưng họ không giải thích về những gì đã xảy ra với họ. Họ có thực sự thiếu sót, và nếu như vậy theo cách nào? Tôi hiện đang viết một số mã sử dụng chúng, vì vậy tôi muốn biết liệu tôi có đang rẽ sai hay không.Sai sót với PipedInputStream/PipedOutputStream

One answer nói:

PipedInputStreamPipedOutputStream bị hỏng (đối với luồng). Họ cho rằng mỗi cá thể được gắn với một chuỗi cụ thể. Đây là kỳ quái.

Đối với tôi, điều đó dường như không kỳ quái và cũng không bị hỏng. Có lẽ tác giả cũng đã có một số sai sót khác trong tâm trí?

Another answer nói:

Trên thực tế họ đang tránh tốt nhất. Tôi đã sử dụng chúng một lần trong 13 năm và tôi ước gì tôi đã không.

Nhưng tác giả đó không thể nhớ lại vấn đề là gì.


Giống như tất cả các lớp và đặc biệt là các lớp được sử dụng trong nhiều chủ đề, bạn sẽ gặp sự cố nếu bạn lạm dụng chúng. Vì vậy, tôi không xem xét không thể đoán trước "write end dead" IOException rằng PipedInputStream có thể ném là một lỗ hổng (không close() kết nối PipedOutputStream là một lỗi; xem bài viết Whats this? IOException: Write end dead, bởi Daniel Ferbers, để biết thêm thông tin). Lỗ hổng khác được yêu cầu là gì?

+0

http://stackoverflow.com/questions/484119/why-doesnt-more-java-code-use-pipedinputstream-pipedoutputstream loại bao quát nó. Họ không thực sự "thiếu sót", chỉ cần một chút khôn lanh và cũng thường là một mùi mã đăng nhập, nếu bạn chắc chắn 100% bạn cần chúng và rằng không có lỗi trong thiết kế, không có vấn đề thực sự với việc sử dụng chúng ... – TC1

+1

Giao diện nhanh như tôi muốn sử dụng. Đó là ít nhất "Dưới nổi bật" là chủ đề đọc không thực sự chờ đợi cho các chủ đề viết để viết yêu cầu đọc đầy đủ, và hủy bỏ với ngoại lệ EOF nếu người viết đóng nó vv Nó có xử lý chủ đề rất nguyên thủy và đồng bộ hóa, và yêu cầu bộ đệm lớn như yêu cầu đọc lớn nhất. – peterk

Trả lời

10

Chúng không hoàn hảo.

Giống như với tất cả các lớp và đặc biệt là các lớp được sử dụng trong nhiều chủ đề, bạn sẽ gặp sự cố nếu bạn lạm dụng chúng. Không thể đoán trước "viết cuối chết" IOException rằng PipedInputStream có thể ném không phải là một lỗ hổng (không close() kết nối PipedOutputStream là một lỗi; xem bài viết Whats this? IOException: Write end dead, bởi Daniel Ferbers, để biết thêm thông tin).

+0

Tôi muốn bạn có ý kiến ​​về một vấn đề tôi mới gặp phải. Bạn có thể vui lòng xem? http://stackoverflow.com/questions/21884188/android-pipedinputstream-messes-up-data – fabian

3

Tôi đã sử dụng chúng một cách độc đáo trong dự án của mình và chúng vô giá để sửa đổi luồng khi di chuyển và truyền chúng đi xung quanh. Hạn chế duy nhất có vẻ là PipedInputStream có một bộ đệm ngắn (khoảng 1024) và dòng đầu ra của tôi đã bơm khoảng 8KB.

Không có khiếm khuyết với nó và nó hoạt động hoàn hảo tốt.

Ví dụ -------- trong groovy

public class Runner{ 


final PipedOutputStream source = new PipedOutputStream(); 
PipedInputStream sink = new PipedInputStream(); 

public static void main(String[] args) { 
    new Runner().doit() 
    println "Finished main thread" 
} 


public void doit() { 

    sink.connect(source) 

    (new Producer(source)).start() 
    BufferedInputStream buffer = new BufferedInputStream(sink) 
    (new Consumer(buffer)).start() 
} 
} 

class Producer extends Thread { 


OutputStream source 
Producer(OutputStream source) { 
    this.source=source 
} 

@Override 
public void run() { 

    byte[] data = new byte[1024]; 

    println "Running the Producer..." 
    FileInputStream fout = new FileInputStream("/Users/ganesh/temp/www/README") 

    int amount=0 
    while((amount=fout.read(data))>0) 
    { 
     String s = new String(data, 0, amount); 
     source.write(s.getBytes()) 
     synchronized (this) { 
      wait(5); 
     } 
    } 

    source.close() 
} 

}

class Consumer extends Thread{ 

InputStream ins 

Consumer(InputStream ins) 
{ 
    this.ins = ins 
} 

public void run() 
{ 
    println "Consumer running" 

    int amount; 
    byte[] data = new byte[1024]; 
    while ((amount = ins.read(data)) >= 0) { 
     String s = new String(data, 0, amount); 
     println "< $s" 
     synchronized (this) { 
      wait(5); 
     } 
    } 

} 

}

+0

sink.close() bị bỏ qua? – zeugor

-2

Từ quan điểm của tôi có một lỗ hổng. Chính xác hơn là có nguy cơ bị bế tắc cao nếu Chủ đề nên bơm dữ liệu vào PipedOutputStream chết sớm trước khi nó thực sự ghi một byte vào luồng. Vấn đề trong tình huống như vậy là việc thực hiện các luồng đường ống không thể phát hiện đường ống bị hỏng. Do đó, việc đọc chuỗi từ PipedInputStream sẽ chờ mãi mãi (tức làbế tắc) trong lần gọi đầu tiên để đọc().

Phát hiện đường ống bị hỏng thực sự dựa vào lệnh gọi đầu tiên để ghi() khi triển khai sẽ lười hơn khởi tạo luồng ghi và chỉ từ điểm đó trong lúc phát hiện đường ống bị hỏng sẽ hoạt động.

Các mã sau tái tạo tình hình:

import java.io.IOException; 
import java.io.PipedInputStream; 
import java.io.PipedOutputStream; 

import org.junit.Test; 

public class PipeTest 
{ 
    @Test 
    public void test() throws IOException 
    { 
     final PipedOutputStream pout = new PipedOutputStream(); 
     PipedInputStream pin = new PipedInputStream(); 

     pout.connect(pin); 

     Thread t = new Thread(new Runnable() 
     { 
      public void run() 
      { 
       try 
       { 
        if(true) 
        { 
         throw new IOException("asd"); 
        } 
        pout.write(0); // first byte which never get's written 
        pout.close(); 
       } 
       catch(IOException e) 
       { 
        throw new RuntimeException(e); 
       } 
      } 
     }); 
     t.start(); 

     pin.read(); // wait's forever, e.g. deadlocks 
    } 
} 
+0

Bạn muốn các hoạt động viết và đọc của bạn nằm trong các chủ đề độc lập. Để người tiêu dùng không thoát ngay lập tức vì điều kiện chạy đua, tốt nhất bạn nên thực hiện kiểm tra pin.available() để thấy rằng nó lớn hơn 0 trước khi tiến hành thao tác đọc. Sau đó, bạn có thể lặp lại các thao tác sẵn có và đọc cho đến khi có sẵn == 0 một lần nữa. Bạn cũng muốn có xử lý ngoại lệ cho phía đọc trong trường hợp nhà văn ngắt kết nối. –

+0

Mã kiểm tra này không đóng được luồng đầu ra khi có ngoại lệ. Nếu bạn bao quanh nội dung của khối try của bạn với 'try (OutputStream pout_closed = pout) {...}' mã sẽ không bế tắc. –

0

Các sai sót mà tôi nhìn thấy với việc thực hiện JDK là:

1) Không timeout, đọc hoặc viết có thể chặn vô cùng.

2) kiểm soát dưới mức tối ưu hơn khi dữ liệu được chuyển giao (nên được thực hiện chỉ với tuôn ra, hoặc khi đệm tròn đầy)

Vì vậy, tôi đã tạo riêng của tôi để giải quyết, (timeout giá trị trên truyền qua một ThreadLocal) :

PipedOutputStream

Làm thế nào để sử dụng:

PiedOutputStreamTest

Hy vọng điều này sẽ giúp ...

Các vấn đề liên quan