জাভাতে টাইমআউট সহ আমি কীভাবে কিছু ব্লকিং পদ্ধতি কল করব?


97

জাভাতে টাইমআউট সহ কোনও ব্লকিং পদ্ধতিটি কল করার কোনও আদর্শ উপায় আছে? আমি করতে সক্ষম হতে চাই:

// call something.blockingMethod();
// if it hasn't come back within 2 seconds, forget it

যদি তা বোঝা যায়।

ধন্যবাদ


4
একটি রেফারেন্স হিসাবে, ব্রায়ান গোয়েজ পিপি 126 - 134 দ্বারা অনুশীলনে জাভা
কনকুরન્સી দেখুন

উত্তর:


155

আপনি একজন নির্বাহক ব্যবহার করতে পারেন:

ExecutorService executor = Executors.newCachedThreadPool();
Callable<Object> task = new Callable<Object>() {
   public Object call() {
      return something.blockingMethod();
   }
};
Future<Object> future = executor.submit(task);
try {
   Object result = future.get(5, TimeUnit.SECONDS); 
} catch (TimeoutException ex) {
   // handle the timeout
} catch (InterruptedException e) {
   // handle the interrupts
} catch (ExecutionException e) {
   // handle other exceptions
} finally {
   future.cancel(true); // may or may not desire this
}

যদি future.get5 সেকেন্ডের মধ্যে ফিরে না আসে তবে এটি একটি নিক্ষেপ করে TimeoutException। সময়সীমাটি সেকেন্ড, মিনিট, মিলিসেকেন্ডে বা কোনও ধ্রুবক হিসাবে উপলব্ধ যে কোনও ইউনিটে কনফিগার করা যায় TimeUnit

আরও বিশদে জাভাডোক দেখুন See


13
ব্লকিং পদ্ধতিটি সময়সীমা পেরিয়ে যাওয়ার পরেও চলতে থাকবে, তাই না?
ইভান দুব্রভ

4
এটি ভবিষ্যতের উপর নির্ভর করে। সেই সময়ে ব্লকিং পদ্ধতিটি কী করছে তার উপর নির্ভর করে এটি শেষ হতে পারে বা নাও পারে।
স্কাফম্যান

4
আমি কীভাবে ব্লকিংমাথড () এ প্যারামিটারটি পাস করতে পারি? ধন্যবাদ!
রবার্ট এ হেনরু

@ রবার্টহেনরু: একটি নতুন ক্লাস তৈরি করুন BlockingMethodCallableযার নামকরণকারী আপনি যে প্যারামিটারগুলিতে পাস করতে চান তা গ্রহণ করে blockingMethod()এবং তাদেরকে সদস্য ভেরিয়েবল (সম্ভবত চূড়ান্ত হিসাবে) হিসাবে সঞ্চয় করতে চান । তারপরে ভিতরে call()সেই পরামিতিগুলি পাস করুন blockMethod()
ভাইট ফ্যালকন

4
অবশেষে করা উচিত future.cancel(true)- ফিউচার <ওজেক্ট> টাইপ পদ্ধতিটি বাতিল (বুলেটিয়ান) যুক্তিগুলির জন্য প্রযোজ্য নয় ()
নোয়াম মানস

9

আপনি একটিতে কলটি FutureTaskलपेटতে পারেন এবং গেট () এর টাইমআউট সংস্করণটি ব্যবহার করতে পারেন।

Http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/FutureTask.html দেখুন


4
ফিউচারটাস্ক নিজেই অ্যাসিক্রোনাস নয়, তাই না? এটি নিজেরাই এটি কেবল সিঙ্ক্রোনালি করে কাজ করে, আপনার এটিকে একটি নির্বাহকের সাথে একত্রিত করতে হবে যেমন অ্যাসিঞ্চ আচরণ।
স্কাফম্যান


4

এটি সত্যিই দুর্দান্ত যে লোকেরা এটিকে অনেক উপায়ে বাস্তবায়নের চেষ্টা করে। তবে সত্যটি হচ্ছে, উপায় নেই।

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

সুতরাং আপনার কাছে কেবলমাত্র 3 টি জেনেরিক বিকল্প রয়েছে:

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

  2. জাভা API গুলি অবরুদ্ধ করতে ব্যবহার করুন। নেটওয়ার্কের জন্য উদাহরণস্বরূপ, NIO2 ব্যবহার করুন এবং অবরুদ্ধকরণবিহীন পদ্ধতিগুলি ব্যবহার করুন। কনসোল থেকে পড়ার জন্য স্ক্যানার.হ্যাসনেক্সট (ব্লক করার আগে ইত্যাদি) ব্যবহার করুন etc.

  3. যদি আপনার ব্লকিং কলটি আইও নয়, তবে আপনার যুক্তিযুক্ত, তবে Thread.isInterrupted()এটি বাহ্যিকভাবে বাধা হয়েছে কিনা তা পরীক্ষা করার জন্য আপনি বারবার যাচাই করতে পারেন , এবং thread.interrupt()ব্লকিং থ্রেডে আরও একটি থ্রেড কল করতে পারেন

সমাবর্তন সম্পর্কে এই কোর্স https://www.udemy.com/java-multithreading-concurrency-performance-optimization/?couponCode=CONCURRENCY

আপনি যদি সত্যিই জাভাতে এটি কীভাবে কাজ করে তা বুঝতে চাইলে সত্যিই সেই সমস্ত মৌলিক পদক্ষেপগুলি নিয়ে যায়। এটি আসলে সেই নির্দিষ্ট সীমাবদ্ধতা এবং পরিস্থিতি সম্পর্কে এবং কীভাবে কোনও বক্তৃতাগুলির মধ্যে সেগুলি সম্পর্কে কীভাবে যেতে হয় সে সম্পর্কে আলোচনা করে।

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

আমি আসা করি এটা সাহায্য করবে


3

জাসাবি-দিক লাইব্রেরির সাথে এর জন্য একটি অ্যাসপেক্টজে সমাধানও রয়েছে

@Timeable(limit = 30, unit = TimeUnit.MINUTES)
public Soup cookSoup() {
  // Cook soup, but for no more than 30 minutes (throw and exception if it takes any longer
}

এটি আরও সংক্ষিপ্ততর হতে পারে না, তবে আপনাকে অবশ্যই অ্যাসপেক্টজে-র উপর নির্ভর করতে হবে এবং অবশ্যই এটি আপনার বিল্ড লাইফসাইকেলে প্রবর্তন করতে হবে।

এটি আরও ব্যাখ্যা করে একটি নিবন্ধ রয়েছে: জাভা পদ্ধতি কার্যকর করার সময় সীমাবদ্ধ করুন


1
Thread thread = new Thread(new Runnable() {
    public void run() {
        something.blockingMethod();
    }
});
thread.start();
thread.join(2000);
if (thread.isAlive()) {
    thread.stop();
}

দ্রষ্টব্য, এই স্টপটিকে অবহেলা করা হয়েছে, আরও ভাল বিকল্প হ'ল মেথড () ব্লকিংয়ের অভ্যন্তরে কিছু অস্থির বুলিয়ান পতাকা সেট করা, এটি পরীক্ষা করে এইভাবে বেরিয়ে আসুন:

import org.junit.*;
import java.util.*;
import junit.framework.TestCase;

public class ThreadTest extends TestCase {
    static class Something implements Runnable {
        private volatile boolean stopRequested;
        private final int steps;
        private final long waitPerStep;

        public Something(int steps, long waitPerStep) {
            this.steps = steps;
            this.waitPerStep = waitPerStep;
        }

        @Override
        public void run() {
            blockingMethod();
        }

        public void blockingMethod() {
            try {
                for (int i = 0; i < steps && !stopRequested; i++) {
                    doALittleBit();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        public void doALittleBit() throws InterruptedException {
            Thread.sleep(waitPerStep);
        }

        public void setStopRequested(boolean stopRequested) {
            this.stopRequested = stopRequested;
        }
    }

    @Test
    public void test() throws InterruptedException {
        final Something somethingRunnable = new Something(5, 1000);
        Thread thread = new Thread(somethingRunnable);
        thread.start();
        thread.join(2000);
        if (thread.isAlive()) {
            somethingRunnable.setStopRequested(true);
            thread.join(2000);
            assertFalse(thread.isAlive());
        } else {
            fail("Exptected to be alive (5 * 1000 > 2000)");
        }
    }
}

1

এটা চেষ্টা কর. আরও সহজ সমাধান। গ্যারান্টি দেয় যে ব্লক যদি সময়সীমার মধ্যে কার্যকর না করে। প্রক্রিয়াটি সমাপ্ত হবে এবং একটি ব্যতিক্রম ছোঁড়াবে।

public class TimeoutBlock {

 private final long timeoutMilliSeconds;
    private long timeoutInteval=100;

    public TimeoutBlock(long timeoutMilliSeconds){
        this.timeoutMilliSeconds=timeoutMilliSeconds;
    }

    public void addBlock(Runnable runnable) throws Throwable{
        long collectIntervals=0;
        Thread timeoutWorker=new Thread(runnable);
        timeoutWorker.start();
        do{ 
            if(collectIntervals>=this.timeoutMilliSeconds){
                timeoutWorker.stop();
                throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
            }
            collectIntervals+=timeoutInteval;           
            Thread.sleep(timeoutInteval);

        }while(timeoutWorker.isAlive());
        System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
    }

    /**
     * @return the timeoutInteval
     */
    public long getTimeoutInteval() {
        return timeoutInteval;
    }

    /**
     * @param timeoutInteval the timeoutInteval to set
     */
    public void setTimeoutInteval(long timeoutInteval) {
        this.timeoutInteval = timeoutInteval;
    }
}

উদাহরণ:

try {
        TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
        Runnable block=new Runnable() {

            @Override
            public void run() {
                //TO DO write block of code 
            }
        };

        timeoutBlock.addBlock(block);// execute the runnable block 

    } catch (Throwable e) {
        //catch the exception here . Which is block didn't execute within the time limit
    }

1

আমি আপনাকে এখানে সম্পূর্ণ কোড দিচ্ছি। আমি যে পদ্ধতিতে কল করছি তার জায়গায় আপনি নিজের পদ্ধতিটি ব্যবহার করতে পারেন:

public class NewTimeout {
    public String simpleMethod() {
        return "simple method";
    }

    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        Callable<Object> task = new Callable<Object>() {
            public Object call() throws InterruptedException {
                Thread.sleep(1100);
                return new NewTimeout().simpleMethod();
            }
        };
        Future<Object> future = executor.submit(task);
        try {
            Object result = future.get(1, TimeUnit.SECONDS); 
            System.out.println(result);
        } catch (TimeoutException ex) {
            System.out.println("Timeout............Timeout...........");
        } catch (InterruptedException e) {
            // handle the interrupts
        } catch (ExecutionException e) {
            // handle other exceptions
        } finally {
            executor.shutdown(); // may or may not desire this
        }
    }
}

0

ধরুন blockingMethodকিছু মিলির জন্য কেবল ঘুমান:

public void blockingMethod(Object input) {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

আমার সমাধানটি ব্যবহার wait()এবং synchronizedএটির মতো:

public void blockingMethod(final Object input, long millis) {
    final Object lock = new Object();
    new Thread(new Runnable() {

        @Override
        public void run() {
            blockingMethod(input);
            synchronized (lock) {
                lock.notify();
            }
        }
    }).start();
    synchronized (lock) {
        try {
            // Wait for specific millis and release the lock.
            // If blockingMethod is done during waiting time, it will wake
            // me up and give me the lock, and I will finish directly.
            // Otherwise, when the waiting time is over and the
            // blockingMethod is still
            // running, I will reacquire the lock and finish.
            lock.wait(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

সুতরাং আপনি প্রতিস্থাপন করতে পারেন

something.blockingMethod(input)

প্রতি

something.blockingMethod(input, 2000)

আশা করি এটা সাহায্য করবে.


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