টাইমআউট সহ কোনও ইনপুটস্ট্রিম থেকে পড়া কি সম্ভব?


147

বিশেষত, সমস্যাটি এই জাতীয় পদ্ধতি লিখতে হয়:

int maybeRead(InputStream in, long timeout)

যেখানে ডেটা 'টাইমআউট' মিলি সেকেন্ডের মধ্যে পাওয়া যায়, এবং -2 অন্যথায়, ফেরতের মান in.read () এর সমান হয়। পদ্ধতিটি ফিরে আসার আগে যে কোনও স্পাড থ্রেডগুলি প্রস্থান করতে হবে।

যুক্তি এড়াতে, বিষয়টি এখানে java.io.InputStream, সূর্যের দ্বারা নথিবদ্ধ (যে কোনও জাভা সংস্করণ)। দয়া করে মনে রাখবেন এটি যতটা সহজ দেখাচ্ছে তেমন সহজ নয়। নীচে কিছু তথ্য দেওয়া হয়েছে যা সূর্যের ডকুমেন্টেশন দ্বারা সরাসরি সমর্থিত।

  1. In.read () পদ্ধতিটি অবিচ্ছিন্ন হতে পারে।

  2. ইনপুট স্ট্রিমটিকে একটি রিডার বা ইন্ট্রিপ্টিবেবল চ্যানেল মোড়ানো কোনও উপকারে আসে না, কারণ এই সমস্ত শ্রেণিগুলি কি করতে পারে তা হল ইনপুট স্ট্রিমের কল পদ্ধতিগুলি methods যদি এই ক্লাসগুলি ব্যবহার করা সম্ভব হয় তবে কোনও সমাধান লিখতে পারা যা কেবল ইনপুটস্ট্রিমে সরাসরি একই যুক্তি সম্পাদন করে।

  3. এটি সর্বদা গ্রহণযোগ্য নয় (ailable

  4. In.close () পদ্ধতিটি ব্লক বা কিছু করতে পারে না।

  5. অন্য থ্রেড মারার কোনও সাধারণ উপায় নেই।

উত্তর:


83

ইনপুটস্ট্রিম ব্যবহার করা হচ্ছে av উপলব্ধ ()

এটি System.in. সর্বদা গ্রহণযোগ্য (0) ফেরত পাওয়া যায়।

আমি বিপরীতটি পেয়েছি - এটি সর্বদা উপলভ্য বাইটের সংখ্যার জন্য সর্বোত্তম মান প্রদান করে। জাভাডোক এর জন্য InputStream.available():

Returns an estimate of the number of bytes that can be read (or skipped over) 
from this input stream without blocking by the next invocation of a method for 
this input stream.

সময় / বাসি থাকার কারণে একটি অনুমান অপরিহার্য। চিত্রটি এক-অফ-অবমূল্যায়ন হতে পারে কারণ নতুন ডেটা প্রতিনিয়ত আগত হয়। তবে এটি সর্বদা পরবর্তী কলটিতে "ক্যাচ আপ" - এটি সমস্ত আগত ডেটার জন্য অ্যাকাউন্ট হওয়া উচিত, বারটি যা নতুন কল করার মুহুর্তে আসে। তথ্য থাকা অবস্থায় স্থায়ীভাবে 0 ফিরিয়ে দেওয়া উপরের শর্তটি ব্যর্থ করে।

প্রথম ক্যাভেট: ইনপুট স্ট্রিমের কংক্রিট সাবক্লাসগুলি উপলভ্য জন্য দায়বদ্ধ ()

InputStreamএকটি বিমূর্ত শ্রেণি। এটির কোনও ডেটা উত্স নেই। এটি উপলভ্য ডেটা থাকা অর্থহীন। অতএব, জাভাদোক available()এছাড়াও বলে:

The available method for class InputStream always returns 0.

This method should be overridden by subclasses.

এবং প্রকৃতপক্ষে, কংক্রিট ইনপুট স্ট্রিম ক্লাসগুলি ধ্রুবক 0 টি নয়, অর্থবহ মানগুলি সরবরাহ করে () উপলভ্য করে।

দ্বিতীয় ক্যাভেট: উইন্ডোজ ইনপুট টাইপ করার সময় আপনি ক্যারেজ-রিটার্ন ব্যবহার করবেন তা নিশ্চিত করুন।

যদি ব্যবহার করা হয় System.in, আপনার প্রোগ্রামটি কেবল তখনই ইনপুট পায় যখন আপনার কমান্ড শেলটি এটি দেয় receives যদি আপনি ফাইল পুনঃনির্দেশ / পাইপ ব্যবহার করেন (যেমন কিছু ফাইল> জাভা মাইজাভা অ্যাপ্লিকেশন বা কিছু কম্যান্ড | জাভা মাই জাভা অ্যাপ), তবে ইনপুট ডেটা সাধারণত তত্ক্ষণাত হস্তান্তর করা হয়। তবে, আপনি যদি ম্যানুয়ালি ইনপুট টাইপ করেন তবে ডেটা হস্তান্তর বিলম্বিত হতে পারে। উদাহরণস্বরূপ উইন্ডোজ সেমিডি.এক্সি শেল সহ, ডেটাটি cmd.exe শেলের মধ্যে বাফার হয়। ডেটা কেবল চালানো জাভা প্রোগ্রামে ক্যারিজেস-রিটার্ন (কন্ট্রোল-এম বা <enter>) এর পরে দেওয়া হয়। এটি কার্যকর করার পরিবেশের একটি সীমাবদ্ধতা। অবশ্যই, ইনপুট স্ট্রিম.ভ্যাভলয়েবল () যতক্ষণ শেল ডেটা বাফার করবে ততক্ষণ 0 আসবে - এটি সঠিক আচরণ; সেই সময়ে কোনও উপলভ্য ডেটা নেই। শেল থেকে ডেটা উপলভ্য হওয়ার সাথে সাথেই পদ্ধতিটি একটি মান> ০. এনবি দেয়: সাইগউইন সেমিডি ব্যবহার করে।

সর্বাধিক সমাধান (কোনও অবরুদ্ধকরণ নয়, তাই কোনও সময়সীমা প্রয়োজন নেই)

কেবল এটি ব্যবহার করুন:

    byte[] inputData = new byte[1024];
    int result = is.read(inputData, 0, is.available());  
    // result will indicate number of bytes read; -1 for EOF with no data read.

বা সমতুল্য,

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in, Charset.forName("ISO-8859-1")),1024);
    // ...
         // inside some iteration / processing logic:
         if (br.ready()) {
             int readCount = br.read(inputData, bufferOffset, inputData.length-bufferOffset);
         }

রিচার সলিউশন (সময়সীমার মধ্যে সর্বাধিকভাবে বাফার পূরণ করে)

এটি ঘোষণা করুন:

public static int readInputStreamWithTimeout(InputStream is, byte[] b, int timeoutMillis)
     throws IOException  {
     int bufferOffset = 0;
     long maxTimeMillis = System.currentTimeMillis() + timeoutMillis;
     while (System.currentTimeMillis() < maxTimeMillis && bufferOffset < b.length) {
         int readLength = java.lang.Math.min(is.available(),b.length-bufferOffset);
         // can alternatively use bufferedReader, guarded by isReady():
         int readResult = is.read(b, bufferOffset, readLength);
         if (readResult == -1) break;
         bufferOffset += readResult;
     }
     return bufferOffset;
 }

তারপরে এটি ব্যবহার করুন:

    byte[] inputData = new byte[1024];
    int readCount = readInputStreamWithTimeout(System.in, inputData, 6000);  // 6 second timeout
    // readCount will indicate number of bytes read; -1 for EOF with no data read.

1
যদি is.available() > 1024এই পরামর্শ ব্যর্থ হবে। এখানে অবশ্যই স্ট্রিম রয়েছে যা শূন্য ফিরে আসে। উদাহরণস্বরূপ SSLCocket সম্প্রতি পর্যন্ত। আপনি এই উপর নির্ভর করতে পারবেন না।
16:25

কেস 'is.av উপলভ্য ()> 1024' বিশেষভাবে পঠিত দৈর্ঘ্যের মাধ্যমে মোকাবেলা করা হয়।
গ্লেন সেরা

মন্তব্য পুনরায় এসএসএসকেটস ভুল - এটি বাফারে যদি কোনও ডেটা না থাকে তবে এটি 0 টি প্রদান করে। আমার উত্তর অনুযায়ী। জাভাডোক: "যদি সকেটে কোনও বাইট না থাকে এবং সকেটটি বন্ধ ব্যবহার করে বন্ধ না করা হয় তবে তা 0. এ ফিরে আসবে
গ্লেন বেস্ট

@ গ্লেনবেস্ট আমার মন্তব্য এসএসএলএসকেটটি ভুল নয়। সাম্প্রতিক অবধি [আমার জোর] সর্বদা শূন্য ফিরে আসত। আপনি বর্তমানের কথা বলছেন আমি জেএসএসইর পুরো ইতিহাস সম্পর্কে কথা বলছি এবং ২০০২ সালে জাভা ১.৪-এ প্রথম অন্তর্ভুক্ত হওয়ার আগে থেকেই আমি তার সাথে কাজ করেছি ।
মারকুইস লর্ন

লুপের শর্তগুলি "" (যখন। উপলব্ধ () উপলভ্য ()> & & সিস্টেম। কর্নারটাইমমিলিস () <ম্যাকটাইমমিলিস এবং অ্যান্ড ওফারস্ফেস <বিলেথেনথ) - এ আমাকে একটি টন সিপিইউ ওভারহেড সংরক্ষণ করেছে to
লজিক 1

65

ধরে Socket.setSoTimeout()নিচ্ছি যে আপনার স্ট্রিমটি কোনও সকেট দ্বারা সমর্থনযোগ্য নয় (যাতে আপনি ব্যবহার করতে পারবেন না ), আমি মনে করি যে এই ধরণের সমস্যা সমাধানের মানক উপায় হল ফিউচার ব্যবহার করা।

ধরুন আমার কাছে নিম্নলিখিত নির্বাহক এবং স্ট্রিম রয়েছে:

    ExecutorService executor = Executors.newFixedThreadPool(2);
    final PipedOutputStream outputStream = new PipedOutputStream();
    final PipedInputStream inputStream = new PipedInputStream(outputStream);

আমার কাছে এমন লেখক রয়েছে যা কিছু তথ্য লিখে তারপরে ডেটা শেষ টুকরো লেখার আগে এবং স্ট্রিমটি বন্ধ করার আগে 5 সেকেন্ড অপেক্ষা করে:

    Runnable writeTask = new Runnable() {
        @Override
        public void run() {
            try {
                outputStream.write(1);
                outputStream.write(2);
                Thread.sleep(5000);
                outputStream.write(3);
                outputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    executor.submit(writeTask);

এটি পড়ার স্বাভাবিক পদ্ধতিটি নীচে রয়েছে। পঠন তথ্যের জন্য অনির্দিষ্টকালের জন্য অবরুদ্ধ হবে এবং সুতরাং এটি 5s এ সম্পূর্ণ হয়:

    long start = currentTimeMillis();
    int readByte = 1;
    // Read data without timeout
    while (readByte >= 0) {
        readByte = inputStream.read();
        if (readByte >= 0)
            System.out.println("Read: " + readByte);
    }
    System.out.println("Complete in " + (currentTimeMillis() - start) + "ms");

কোন ফলাফল:

Read: 1
Read: 2
Read: 3
Complete in 5001ms

যদি আরও মৌলিক সমস্যা থাকে যেমন লেখক সাড়া না দেয় তবে পাঠক চিরকালের জন্য অবরুদ্ধ হয়ে যায়। আমি যদি ভবিষ্যতে পঠনটি গুটিয়ে রাখি তবে আমি টাইমআউটটি নিম্নরূপে নিয়ন্ত্রণ করতে পারি:

    int readByte = 1;
    // Read data with timeout
    Callable<Integer> readTask = new Callable<Integer>() {
        @Override
        public Integer call() throws Exception {
            return inputStream.read();
        }
    };
    while (readByte >= 0) {
        Future<Integer> future = executor.submit(readTask);
        readByte = future.get(1000, TimeUnit.MILLISECONDS);
        if (readByte >= 0)
            System.out.println("Read: " + readByte);
    }

কোন ফলাফল:

Read: 1
Read: 2
Exception in thread "main" java.util.concurrent.TimeoutException
    at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:228)
    at java.util.concurrent.FutureTask.get(FutureTask.java:91)
    at test.InputStreamWithTimeoutTest.main(InputStreamWithTimeoutTest.java:74)

আমি টাইমআউটএক্সেপশন ধরতে পারি এবং যা চাই পরিষ্কার করতে পারি।


14
তবে ব্লকিং থ্রেডের কী হবে ?! অ্যাপ্লিকেশন শেষ না হওয়া পর্যন্ত এটি কি স্মৃতিতে থাকবে? আমি যদি সঠিক হয়ে থাকি তবে এটি অফুরন্ত থ্রেড তৈরি করতে পারে অ্যাপ্লিকেশনটি ভারী বোঝা এবং আরও বেশি, আপনার পুলটি ব্যবহার করতে আরও থ্রেডগুলি অবরুদ্ধ করা উচিত যার থ্রেডগুলি দখল করা এবং অবরুদ্ধ করা হয়েছে। আমি ভুল হলে আমাকে সংশোধন করুন। ধন্যবাদ.
মুহাম্মদ জেলবানা

4
মুহাম্মদ জেলবানা, আপনি ঠিক বলেছেন: ব্লকিং রিড () থ্রেড চলতে থাকে এবং এটি ঠিক নয়। যদিও আমি এটি প্রতিরোধের জন্য একটি উপায় খুঁজে পেয়েছি: যখন টাইমআউট হিট হয়, কলিং থ্রেডটি ইনপুট স্ট্রিমটি বন্ধ করে দেয় (আমার ক্ষেত্রে আমি অ্যান্ড্রয়েড ব্লুটুথ সকেটটি বন্ধ করি যা থেকে ইনপুট স্ট্রিমটি আসে)। আপনি যখন এটি করেন, পঠিত () কলটি তত্ক্ষণাত্ ফিরে আসবে ..আচ্ছা আমার ক্ষেত্রে আমি ইনট রিড (বাইট []] ওভারলোড ব্যবহার করি এবং তা সঙ্গে সঙ্গে ফিরে আসে। হয়তো ইনট রিড () ওভারলোড আইওএক্সেপশন নিক্ষেপ করবে যেহেতু আমি জানি না এটি কী ফিরে আসবে ... আমার মনে এটি সঠিক সমাধান।
ইমানুয়েল টুজারি

5
অ্যাপ্লিকেশন শেষ না হওয়া পর্যন্ত থ্রেড রিডিং অবরুদ্ধ থাকায় -1।
অর্টউইন অ্যাঙ্গারমেয়ার

11
@ortang "টাইমআউটএক্সেপশন ধরুন এবং যাই হোক না কেন পরিষ্কার করুন ..." বলতে আমি বোঝাতে চাইছি এর উদাহরণটি আমি পড়ার থ্রেডটি মেরে ফেলতে চাই: ... ধরা (টাইমআউটএক্সেপশন ই) {এক্সিকিউটার.শুটডাউননিউ (); }
ইয়ান জোন্স

12
executer.shutdownNowথ্রেড হত্যা করবে না। এটি এটিকে বাধা দেওয়ার চেষ্টা করবে, কোনও প্রভাব ছাড়াই। কোনও পরিচ্ছন্নতার সম্ভাবনা নেই এবং এটি একটি গুরুতর বিষয়।
মার্কো টপলনিক

22

যদি আপনার ইনপুট স্ট্রিমটি সকেট দ্বারা ব্যাক হয় তবে আপনি সেটসোটাইমআউট ব্যবহার করে সকেট টাইমআউট (মিলিসেকেন্ডে) সেট করতে পারেন । যদি পঠিত () কলটি নির্দিষ্ট সময়সীমার মধ্যে অবরোধ মুক্ত না করে, এটি একটি সকেটটাইমআউটপ্লেশন নিক্ষেপ করবে।

কেবলমাত্র নিশ্চিত হয়ে নিন যে আপনি পঠিত () কল করার আগে সকেটে সেটসোটাইমআউট কল করেছেন।


18

আমি কেবল অন্ধভাবে গ্রহণ করার চেয়ে সমস্যার বিবৃতিটি প্রশ্ন করব। আপনার কেবল কনসোল বা নেটওয়ার্কের মাধ্যমে সময়সীমা দরকার। যদি আপনি পরে থাকেন Socket.setSoTimeout()এবং HttpURLConnection.setReadTimeout()যা উভয়ই ঠিক যা যা প্রয়োজন ঠিক তা করে, যতক্ষণ আপনি এগুলি সঠিকভাবে সেট আপ করেন যতক্ষণ না আপনি সেগুলি নির্মাণ / অর্জন করেন। আপনার সমস্ত কিছু যখন ইনপুটস্ট্রিমে থাকে তখন অ্যাপ্লিকেশনটিতে এটিকে একটি স্বেচ্ছাসেবী বিন্দুতে রেখে দেওয়া খুব দুর্বল বাস্তবায়নের দিকে পরিচালিত দুর্বল নকশা।


10
অন্যান্য পরিস্থিতি রয়েছে যেখানে কোনও পাঠ্য সম্ভাব্যভাবে একটি উল্লেখযোগ্য সময়ের জন্য অবরুদ্ধ হতে পারে; যেমন কোনও টেপ ড্রাইভ থেকে পড়ার সময়, দূরবর্তীভাবে মাউন্ট করা নেটওয়ার্ক ড্রাইভ থেকে বা পিছনের প্রান্তে একটি টেপ রোবট সহ এইচএফএস থেকে। (তবে আপনার উত্তরের মূল খোঁচা সঠিক))
স্টিফেন সি

1
আপনার মন্তব্য এবং উদাহরণের জন্য @ স্টেফেনসি +1। আপনার উদাহরণ আরও যোগ করার জন্য, সকেট সংযোগগুলি সঠিকভাবে তৈরি করা হলেও একটি সহজ কেস হতে পারে তবে ডিবি থেকে ডেটা আনার কথা পড়ার চেষ্টা অবরুদ্ধ করা হয়েছিল তবে এটি কোনওভাবে ঘটেছিল না (বলুন যে ডিবি সাড়া দিচ্ছিল না এবং কোয়েরি চলে গেল লকড স্টেটে)। এই দৃশ্যে আপনার সকেটের স্পষ্টতই পঠন অপারেশনটির সময়সীমার একটি উপায় থাকা দরকার।
সাফল্য

1
ইনপুটস্ট্রিম বিমূর্তির পুরো বিষয়টি অন্তর্নিহিত বাস্তবায়ন সম্পর্কে চিন্তা না করা। পোস্ট করা উত্তরগুলির পক্ষে মতামত সম্পর্কে তর্ক করার পক্ষে এটি মেলা। কিন্তু, সমস্যা বিবৃতি প্রশ্ন করতে, disussion সাহায্য যাচ্ছে না
pellucide

2
ইনপুট স্ট্রিম একটি স্ট্রিমে কাজ করে এবং এটি অবরুদ্ধ করে, তবুও এটি একটি সময়সীমা প্রক্রিয়া সরবরাহ করে না। সুতরাং ইনপুটস্ট্রিম বিমূর্তি কোনও উপযুক্তভাবে ডিজাইন করা বিমূর্ততা নয়। অতএব কোনও স্ট্রিমের সময়সীমার উপায় জিজ্ঞাসা করা বেশি চাওয়া হয় না। সুতরাং প্রশ্নটি একটি খুব ব্যবহারিক সমস্যার সমাধান চাইছে। অন্তর্নিহিত বেশিরভাগ বাস্তবায়ন অবরুদ্ধ হবে। একটি স্রোতের খুব মূল অংশকে বোঝায়। সকেট, ফাইলস, পাইপগুলি ব্লক করবে যদি স্ট্রিমের অন্য পাশটি নতুন ডেটা সহ প্রস্তুত না হয়।
পেলুসাইড

2
@EJP। আপনি কীভাবে পেলেন তা আমি জানি না। আমি তোমার সাথে একমত হই নি সমস্যার বিবৃতি "কীভাবে একটি ইনপুট স্ট্রিমে টাইমআউট করবেন" বৈধ। যেহেতু ফ্রেমওয়ার্ক সময়সীমা শেষ করার কোনও উপায় সরবরাহ করে না, তাই এই জাতীয় প্রশ্ন জিজ্ঞাসা করা উপযুক্ত।
পেলিউসাইড

7

আমি জাভা এনআইও প্যাকেজ থেকে ক্লাসগুলি ব্যবহার করি নি, তবে মনে হয় তারা এখানে কিছুটা সহায়ক হতে পারে। বিশেষত, java.nio.channels.Channels এবং java.nio.channels.InterruptibleChannel


2
+1: আমি বিশ্বাস করি না যে ওপি একা ইনপুটস্ট্রিমের কাছে যা চেয়েছে তা করার একটি নির্ভরযোগ্য উপায় আছে। তবে নিও অন্যদের মধ্যেও এই উদ্দেশ্যে তৈরি করা হয়েছিল created
এডি

2
ওপি ইতিমধ্যে মূলত এটিকে বাতিল করে দিয়েছে। ইনপুট স্ট্রিমগুলি অন্তর্নিহিতভাবে ব্লক করছে এবং অ-বাধা দিতে পারে।
লার্নের মারকুইস

5

এখানে System.in থেকে এনআইও ফাইলচেনেল পাওয়ার এবং একটি সময়সীমা ব্যবহার করে ডেটার প্রাপ্যতা যাচাই করার একটি উপায় রয়েছে যা প্রশ্নের বর্ণনায় বর্ণিত সমস্যার একটি বিশেষ বিষয়। এটি কনসোলে চালান, কোনও ইনপুট টাইপ করবেন না এবং ফলাফলের জন্য অপেক্ষা করুন। এটি জাভা 6 এর অধীনে উইন্ডোজ এবং লিনাক্সে সফলভাবে পরীক্ষা করা হয়েছিল।

import java.io.FileInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;

public class Main {

    static final ByteBuffer buf = ByteBuffer.allocate(4096);

    public static void main(String[] args) {

        long timeout = 1000 * 5;

        try {
            InputStream in = extract(System.in);
            if (! (in instanceof FileInputStream))
                throw new RuntimeException(
                        "Could not extract a FileInputStream from STDIN.");

            try {
                int ret = maybeAvailable((FileInputStream)in, timeout);
                System.out.println(
                        Integer.toString(ret) + " bytes were read.");

            } finally {
                in.close();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /* unravels all layers of FilterInputStream wrappers to get to the
     * core InputStream
     */
    public static InputStream extract(InputStream in)
            throws NoSuchFieldException, IllegalAccessException {

        Field f = FilterInputStream.class.getDeclaredField("in");
        f.setAccessible(true);

        while( in instanceof FilterInputStream )
            in = (InputStream)f.get((FilterInputStream)in);

        return in;
    }

    /* Returns the number of bytes which could be read from the stream,
     * timing out after the specified number of milliseconds.
     * Returns 0 on timeout (because no bytes could be read)
     * and -1 for end of stream.
     */
    public static int maybeAvailable(final FileInputStream in, long timeout)
            throws IOException, InterruptedException {

        final int[] dataReady = {0};
        final IOException[] maybeException = {null};
        final Thread reader = new Thread() {
            public void run() {                
                try {
                    dataReady[0] = in.getChannel().read(buf);
                } catch (ClosedByInterruptException e) {
                    System.err.println("Reader interrupted.");
                } catch (IOException e) {
                    maybeException[0] = e;
                }
            }
        };

        Thread interruptor = new Thread() {
            public void run() {
                reader.interrupt();
            }
        };

        reader.start();
        for(;;) {

            reader.join(timeout);
            if (!reader.isAlive())
                break;

            interruptor.start();
            interruptor.join(1000);
            reader.join(1000);
            if (!reader.isAlive())
                break;

            System.err.println("We're hung");
            System.exit(1);
        }

        if ( maybeException[0] != null )
            throw maybeException[0];

        return dataReady[0];
    }
}

মজার বিষয় হচ্ছে, কনটোলের পরিবর্তে নেটবিয়ান্স 6.5 এর মধ্যে প্রোগ্রামটি চালানোর সময় সময়সীমাটি মোটেই কার্যকর হয় না এবং জম্বি থ্রেডগুলিকে মেরে ফেলার জন্য System.exit () এ কল করা আসলেই প্রয়োজনীয়। যা ঘটে তা হ'ল রিডার ইন্টেটারপ্ট () তে কলটিতে ইন্ট্যারাপ্টর থ্রেড ব্লক (!) করে। অন্য একটি পরীক্ষা প্রোগ্রাম (এখানে দেখানো হয়নি) অতিরিক্তভাবে চ্যানেলটি বন্ধ করার চেষ্টা করে, তবে সেটিও কার্যকর হয় না।


ম্যাক ওএসে কাজ করে না, জেডিকে 1.6 বা জেডিকে 1.7 দিয়েও কাজ করে না। পড়ার সময় রিটার্ন টিপে কেবল বাধাটি স্বীকৃত।
মোস্তোভস্কি

4

যেমনটি জেটি বলেছে, এনআইও হ'ল সেরা (এবং সঠিক) সমাধান। আপনি যদি সত্যই ইনপুট স্ট্রিমের সাথে আটকে থাকেন তবে আপনি তাও করতে পারেন

  1. ইনপুটস্ট্রিম থেকে পড়া এবং এক ফলাফলকে একটি বাফারে রাখার জন্য একচেটিয়া কাজ যিনি একচেটিয়া কাজ তা এড়িয়ে যান যা আপনাকে অবরুদ্ধ না করে আপনার মূল থ্রেড থেকে পড়তে পারে। আপনার যদি কখনও স্ট্রিমের একটি উদাহরণ থাকে তবে এটি ভালভাবে কাজ করবে। অন্যথায় আপনি থ্রেড শ্রেণিতে অবহেলিত পদ্ধতি ব্যবহার করে থ্রেডটি মারতে সক্ষম হতে পারেন, যদিও এটি সংস্থান ফাঁসের কারণ হতে পারে।

  2. ব্লক না করে পড়া যেতে পারে এমন ডেটা নির্দেশ করতে উপলভ্য নির্ভরতা। তবে কিছু ক্ষেত্রে (যেমন সকেট সহ) এটি 0 এর বাইরে অন্য কিছু জানার জন্য সম্ভাব্য ব্লকিং রিড নিতে পারে A


5
Socket.setSoTimeout()একটি সমান সঠিক এবং অনেক সহজ সমাধান। বা HttpURLConnection.setReadTimeout()
লার্নের মারকুইস

3
@ এজেপি - নির্দিষ্ট পরিস্থিতিতে এগুলি কেবল "সমানভাবে সঠিক"; যেমন যদি ইনপুট স্ট্রিমটি সকেট স্ট্রিম / এইচটিটিপি সংযোগ স্ট্রিম হয় stream
স্টিফেন সি

1
@ স্টেফেন সি এনআইও কেবল একই পরিস্থিতিতে অবরুদ্ধ এবং নির্বাচনযোগ্য। উদাহরণস্বরূপ কোনও অবরুদ্ধকরণ ফাইল I / O নেই।
লার্নের মারকুইস

2
@ ইজেপি কিন্তু অ-ব্লকিং পাইপ আইও (System.in) রয়েছে, ফাইলগুলির জন্য লো-ব্লকিং I / O নেই (লোকাল ডিস্কে)
বোকামি

1
@ ইজেপি অন সর্বাধিক (সমস্ত?) ইউনিসিস সিস্টেমে আসলে একটি পাইপ (যদি আপনি শেলটিকে ফাইলের সাথে প্রতিস্থাপন করতে বলেন না) এবং পাইপ হিসাবে এটি অ-ব্লকিং হতে পারে।
উদ্দীপ্ত

0

এই উত্তরে অনুপ্রাণিত আমি আরও কিছু অবজেক্ট-ভিত্তিক সমাধান নিয়ে এসেছি।

আপনি কেবলমাত্র অক্ষর পড়ার ইচ্ছা থাকলেই এটি বৈধ

আপনি বাফারড্রেডারকে ওভাররাইড করতে পারেন এবং এর মতো কিছু বাস্তবায়ন করতে পারেন:

public class SafeBufferedReader extends BufferedReader{

    private long millisTimeout;

    ( . . . )

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(cbuf, off, len);
    }

    protected void waitReady() throws IllegalThreadStateException, IOException {
        if(ready()) return;
        long timeout = System.currentTimeMillis() + millisTimeout;
        while(System.currentTimeMillis() < timeout) {
            if(ready()) return;
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                break; // Should restore flag
            }
        }
        if(ready()) return; // Just in case.
        throw new IllegalThreadStateException("Read timed out");
    }
}

এখানে একটি প্রায় সম্পূর্ণ উদাহরণ।

আমি কয়েকটি পদ্ধতিতে 0 ফিরিয়ে দিচ্ছি, আপনার প্রয়োজনীয়তাগুলি পূরণ করার জন্য আপনার এটি পরিবর্তন করে -2 করা উচিত, তবে আমি মনে করি যে বাফারডারার চুক্তিতে 0 টি আরও উপযুক্ত। কিছুই ভুল হয়নি, এটি কেবল 0 টি অক্ষর পড়েন। রিডলাইন পদ্ধতিটি একটি ভয়ঙ্কর পারফরম্যান্স হত্যাকারী। আপনি যদি রিডলিনটি প্রকৃতপক্ষে ব্যবহার করতে চান তবে আপনার সম্পূর্ণ নতুন বাফারডারিডার তৈরি করা উচিত ই । এখনই, এটি থ্রেড নিরাপদ নয়। রিডলাইনগুলি কোনও লাইনের জন্য অপেক্ষা করতে থাকা অবস্থায় যদি কেউ অপারেশনের জন্য আবেদন করে তবে এটি অপ্রত্যাশিত ফলাফল আনবে

আমি যেখানে থাকি -2 ফিরতে পছন্দ করি না। আমি একটি ব্যতিক্রম ছুঁড়েছি কারণ কিছু লোক EOS বিবেচনা করার জন্য কেবল << 0 পরীক্ষা করছে। যাইহোক, এই পদ্ধতিগুলি দাবি করে যে "অবরুদ্ধ করতে পারে না", আপনার এই বিবৃতিটি সত্য এবং ঠিক ওভাররাইড করা উচিত নয় কিনা তা পরীক্ষা করা উচিত।

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

/**
 * 
 * readLine
 * 
 * @author Dario
 *
 */
public class SafeBufferedReader extends BufferedReader{

    private long millisTimeout;

    private long millisInterval = 100;

    private int lookAheadLine;

    public SafeBufferedReader(Reader in, int sz, long millisTimeout) {
        super(in, sz);
        this.millisTimeout = millisTimeout;
    }

    public SafeBufferedReader(Reader in, long millisTimeout) {
        super(in);
        this.millisTimeout = millisTimeout;
    }



    /**
     * This is probably going to kill readLine performance. You should study BufferedReader and completly override the method.
     * 
     * It should mark the position, then perform its normal operation in a nonblocking way, and if it reaches the timeout then reset position and throw IllegalThreadStateException
     * 
     */
    @Override
    public String readLine() throws IOException {
        try {
            waitReadyLine();
        } catch(IllegalThreadStateException e) {
            //return null; //Null usually means EOS here, so we can't.
            throw e;
        }
        return super.readLine();
    }

    @Override
    public int read() throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return -2; // I'd throw a runtime here, as some people may just be checking if int < 0 to consider EOS
        }
        return super.read();
    }

    @Override
    public int read(char[] cbuf) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return -2;  // I'd throw a runtime here, as some people may just be checking if int < 0 to consider EOS
        }
        return super.read(cbuf);
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(cbuf, off, len);
    }

    @Override
    public int read(CharBuffer target) throws IOException {
        try {
            waitReady();
        } catch(IllegalThreadStateException e) {
            return 0;
        }
        return super.read(target);
    }

    @Override
    public void mark(int readAheadLimit) throws IOException {
        super.mark(readAheadLimit);
    }

    @Override
    public Stream<String> lines() {
        return super.lines();
    }

    @Override
    public void reset() throws IOException {
        super.reset();
    }

    @Override
    public long skip(long n) throws IOException {
        return super.skip(n);
    }

    public long getMillisTimeout() {
        return millisTimeout;
    }

    public void setMillisTimeout(long millisTimeout) {
        this.millisTimeout = millisTimeout;
    }

    public void setTimeout(long timeout, TimeUnit unit) {
        this.millisTimeout = TimeUnit.MILLISECONDS.convert(timeout, unit);
    }

    public long getMillisInterval() {
        return millisInterval;
    }

    public void setMillisInterval(long millisInterval) {
        this.millisInterval = millisInterval;
    }

    public void setInterval(long time, TimeUnit unit) {
        this.millisInterval = TimeUnit.MILLISECONDS.convert(time, unit);
    }

    /**
     * This is actually forcing us to read the buffer twice in order to determine a line is actually ready.
     * 
     * @throws IllegalThreadStateException
     * @throws IOException
     */
    protected void waitReadyLine() throws IllegalThreadStateException, IOException {
        long timeout = System.currentTimeMillis() + millisTimeout;
        waitReady();

        super.mark(lookAheadLine);
        try {
            while(System.currentTimeMillis() < timeout) {
                while(ready()) {
                    int charInt = super.read();
                    if(charInt==-1) return; // EOS reached
                    char character = (char) charInt;
                    if(character == '\n' || character == '\r' ) return;
                }
                try {
                    Thread.sleep(millisInterval);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt(); // Restore flag
                    break;
                }
            }
        } finally {
            super.reset();
        }
        throw new IllegalThreadStateException("readLine timed out");

    }

    protected void waitReady() throws IllegalThreadStateException, IOException {
        if(ready()) return;
        long timeout = System.currentTimeMillis() + millisTimeout;
        while(System.currentTimeMillis() < timeout) {
            if(ready()) return;
            try {
                Thread.sleep(millisInterval);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // Restore flag
                break;
            }
        }
        if(ready()) return; // Just in case.
        throw new IllegalThreadStateException("read timed out");
    }

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.