থ্রেড থেকে প্রত্যাবর্তন মান


97

আমার সাথে একটি পদ্ধতি আছে HandlerThread। এর মধ্যে একটি মান পরিবর্তিত হয় Threadএবং আমি এটি test()পদ্ধতিতে ফিরিয়ে দিতে চাই । এই কাজ করতে একটি উপায় আছে কি?

public void test()
{   
    Thread uiThread = new HandlerThread("UIHandler"){
        public synchronized void run(){
            int value; 
            value = 2; //To be returned to test()
        }
    };
    uiThread.start();
}

যদি মূল থ্রেডটি পদ্ধতি থেকে ফিরে আসার আগে হ্যান্ডলার থ্রেডটি শেষ হওয়ার অপেক্ষা করে থাকে তবে প্রথম স্থানে হ্যান্ডলার থ্রেডটি কেন ব্যবহার করবেন?
জেবি নিজেট

4
@ জেবিনিজেট আমি থ্রেডটি আসলে কী করে তার জটিলতায় অন্তর্ভুক্ত করিনি। এটি জিপিএসের সমন্বয়গুলি পেয়েছে তাই হ্যাঁ আমার একটি থ্রেডের দরকার নেই।
নীতা

4
থ্রেডের জটিলতা নির্বিশেষে, থ্রেড যেটি সূচিত করে তা যদি তাৎক্ষণিকভাবে শুরু করার পরে তার ফলাফলের জন্য অপেক্ষা করে, তবে আলাদা থ্রেড শুরু করার কোনও অর্থ নেই: প্রারম্ভিক থ্রেডটি ব্লক হয়ে যাবে যেন এটি নিজেই কাজ করেছিল।
জেবি নিজেট

পছন্দ করেছেন
নীতা

4
একটি থ্রেড ব্যাকগ্রাউন্ডে কিছু কার্যকর করতে সক্ষম হতে এবং পটভূমি থ্রেড কার্যকর করার সময় অন্য কিছু করতে সক্ষম হতে ব্যবহৃত হয়। যদি আপনি কোনও থ্রেড শুরু করেন, এবং থ্রেডটি বন্ধ না হওয়া অবধি অবিলম্বে অবরুদ্ধ করুন, আপনি নিজেই থ্রেড দ্বারা করা কাজটি করতে পারেন এবং এটি কোনও সরলতা ছাড়াই কোনও পার্থক্য করবে না except
জেবি নিজেট

উত্তর:


77

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

public void test()
{   
    final CountDownLatch latch = new CountDownLatch(1);
    final int[] value = new int[1];
    Thread uiThread = new HandlerThread("UIHandler"){
        @Override
        public void run(){
            value[0] = 2;
            latch.countDown(); // Release await() in the test thread.
        }
    };
    uiThread.start();
    latch.await(); // Wait for countDown() in the UI thread. Or could uiThread.join();
    // value[0] holds 2 at this point.
}

এছাড়াও আপনি একটি ব্যবহার করতে পারেন Executorএবং একটি Callableভালো:

public void test() throws InterruptedException, ExecutionException
{   
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Callable<Integer> callable = new Callable<Integer>() {
        @Override
        public Integer call() {
            return 2;
        }
    };
    Future<Integer> future = executor.submit(callable);
    // future.get() returns 2 or raises an exception if the thread dies, so safer
    executor.shutdown();
}

4
উম ... না এই কোডটি সঠিক নয়। মান অ্যাক্সেস সঠিকভাবে সিঙ্ক্রোনাইজ করা হয় না।
জি ব্লেক মাইক

6
কাউন্টডাউনল্যাচের মেমরি ধারাবাহিকতা গ্যারান্টির কারণে অ্যাক্সেসগুলি মূল্য দেওয়ার জন্য আমাদের প্রকৃতপক্ষে সুসংগত সংশ্লেষের প্রয়োজন নেই। মান অ্যারে তৈরির ঘটনাটি ঘটে - ইউআইথ্রেড শুরুর আগে (প্রোগ্রামের আদেশের নিয়ম) যা সিঙ্ক্রোনাইজ করে 2-এর মান [0] ( থ্রেড শুরু ) এর সাথে সংঘবদ্ধ হয় যা ঘটে ল্যাচকাউন্টডাউন () (প্রোগ্রাম অর্ডার রুল) এর আগে যা ঘটে ল্যাচ করার আগে .Avit () (কাউন্টডাউনল্যাচ থেকে গ্যারান্টি) যা ঘটে [মানচিত্রের শৃঙ্খলার আগে (প্রোগ্রাম অর্ডার বিধি)) happens
অ্যাডাম জালকম্যান

দেখে মনে হচ্ছে আপনি ম্যাচটি ঠিক বলেছেন! ... যে ক্ষেত্রে, রান পদ্ধতির সিঙ্ক্রোনাইজেশন অকেজো।
জি ব্লেক মাইক

ভাল যুক্তি. আমার অবশ্যই ওপির কোড থেকে কপি-পেস্ট করা উচিত। সংশোধন করা হয়েছে।
অ্যাডাম জালকম্যান

এখানে কাউন্টডাউনল্যাচের উদাহরণ রয়েছে: developer.android.com/references/java/util/concurrent/…
সিগল

92

সাধারণত আপনি এটি কিছু এই করতে হবে

 public class Foo implements Runnable {
     private volatile int value;

     @Override
     public void run() {
        value = 2;
     }

     public int getValue() {
         return value;
     }
 }

তারপরে আপনি থ্রেড তৈরি করতে এবং মানটি পুনরুদ্ধার করতে পারেন (মান নির্ধারণ করা হয়েছে যে দেওয়া হয়েছে)

Foo foo = new Foo();
Thread thread = new Thread(foo);
thread.start();
thread.join();
int value = foo.getValue();

tl;drএকটি থ্রেড কোনও মান ফেরত দিতে পারে না (কমপক্ষে কলব্যাক প্রক্রিয়া ছাড়াই নয়)। আপনার একটি সাধারণ শ্রেণীর মতো একটি থ্রেড উল্লেখ করা উচিত এবং তার জন্য মূল্য জিজ্ঞাসা করা উচিত।


4
এটি কি সত্যিই কাজ করে? আমি পেতে The method getValue() is undefined for the type Thread
pmichna

4
@ পিচ্চিনা, ভাল স্পটিং থেকে পরিবর্তন করা t.getValue()হচ্ছে foo.getValue()
জোহান সিজবার্গ

4
হ্যাঁ! সাবাশ! "অস্থির" ftw! গৃহীত উত্তরের মতো নয়, এটি সঠিক!
জি ব্লেক মাইক

11
@HamzahMalik নিশ্চিত থ্রেড শেষ ব্যবহারের জন্য Thread t = new Thread(foo); t.start(); t.join(); foo.getValue();t.join()থ্রেড পর্যন্ত ব্লক সমাপ্ত হয়।
ড্যানিয়েল

4
@ হারিকিরান হ্যাঁ সঠিক, প্রতিটি থ্রেড একটি পৃথক মান প্রদান করে।
রুট এক্সপ্লোরার

29

আপনি যা খুঁজছেন সম্ভবত এটির Callable<V>স্থানের ইন্টারফেস এবং Runnableকোনও Future<V>বস্তুর সাথে মান পুনরুদ্ধার , যা আপনাকে মানটি গণনা না করা পর্যন্ত অপেক্ষা করতে দেয়। আপনি এটির মাধ্যমে এটি অর্জন ExecutorServiceকরতে পারেন, যা আপনি এটি থেকে পেতে পারেন Executors.newSingleThreadExecutor()

public void test() {
    int x;
    ExecutorService es = Executors.newSingleThreadExecutor();
    Future<Integer> result = es.submit(new Callable<Integer>() {
        public Integer call() throws Exception {
            // the other thread
            return 2;
        }
    });
    try {
        x = result.get();
    } catch (Exception e) {
        // failed
    }
    es.shutdown();
}

8

কীভাবে এই সমাধান?

এটি থ্রেড ক্লাস ব্যবহার করে না, তবে এটি একযোগে হয় এবং একভাবে এটি আপনার অনুরোধের মতো করে

ExecutorService pool = Executors.newFixedThreadPool(2); // creates a pool of threads for the Future to draw from

Future<Integer> value = pool.submit(new Callable<Integer>() {
    @Override
    public Integer call() {return 2;}
});

এখন আপনি যা করছেন তা হ'ল value.get()যখনই আপনার ফিরে আসা মানটি ধরার দরকার হবে তখন থ্রেডটি শুরু হয় আপনি খুব valueএকটা মান দেন যাতে আপনাকে এর threadName.start()উপর আর বলতে হবে না।

কী এক Future, একটি হল প্রতিশ্রুতি প্রোগ্রাম, আপনি প্রোগ্রাম কারণ এটি টিপস মান এটা অদূর ভবিষ্যতে একদা প্রয়োজন পাবেন

.get()এটি সম্পন্ন হওয়ার আগে আপনি যদি এটির জন্য কল করেন তবে যে থ্রেড এটি কল করছে এটি কেবল এটি শেষ না হওয়া পর্যন্ত অপেক্ষা করবে


আমি প্রদত্ত কোডটি দুটি বিষয়কে পৃথক করেছিলাম একটি হ'ল পুলের দীক্ষা যা আমি অ্যাপ্লিকেশন ক্লাসে করি (আমি অ্যান্ড্রয়েডের কথা বলছি) এবং দ্বিতীয়ত আমি যে জায়গাগুলি আমার প্রয়োজন সেখানে পুলটি ব্যবহার করি ... এছাড়াও এক্সিকিউটার্স.নেউফিক্সডথ্রেডপুল ব্যবহার সম্পর্কেও ( 2) আমি এক্সিকিউটার্স.নেউসিংলথ্রেডএ্যাক্সিকিউটর () ব্যবহার করেছি .. যেহেতু সার্ভার কলগুলির জন্য আমার একসাথে কেবলমাত্র একটি কাজ চলমান ছিল ... আপনার উত্তরটি নিখুঁত @ ইলেক্ট্রিক সর্বাধিক কফি ধন্যবাদ
গৌরব পাঙ্গাম

@ ইলেক্ট্রিক আপনি কীভাবে জানবেন যে কখন মূল্য পাবেন? আমি বিশ্বাস করি যে আসল পোস্টারটি তার পদ্ধতিতে এই মানটি ফিরিয়ে দিতে চেয়েছিল। .Get () কলটি ব্যবহার করে মানটি পুনরুদ্ধার করবে তবে কেবল অপারেশন সম্পন্ন হলে। সে কোনও অন্ধ .get () কল দিয়ে জানত না
Portfoliobuilder

4

আপনি যদি কলিং পদ্ধতি থেকে মানটি চান, তবে থ্রেডটি শেষ হওয়ার অপেক্ষা করা উচিত, যা থ্রেডগুলি কিছুটা অর্থহীন করে তোলে।

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

প্রশ্নের কোডটিতে একটি সামান্য নোট: প্রসারিত Threadকরা সাধারণত দুর্বল শৈলী। অযথা ক্লাস প্রসারিত করা একটি খারাপ ধারণা। আমি লক্ষ্য করেছি runযে কোনও কারণে আপনার পদ্ধতিটি সিঙ্ক্রোনাইজ হয়েছে। এখন এই ক্ষেত্রে অবজেক্টটি হ'ল Threadআপনি Threadতার লকটি যা ব্যবহার করেন তা হস্তক্ষেপ করতে পারেন (রেফারেন্স বাস্তবায়নে join, আইআইআরসি-তে কিছু করার জন্য )।


"তারপরে থ্রেডটি শেষ হওয়ার অপেক্ষা করা উচিত, যা থ্রেডগুলি কিছুটা অর্থহীন করে তোলে" দুর্দান্ত পয়েন্ট!
likejudo

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

3

জাভা 8 এর পরে আমাদের আছে CompletableFuture। আপনার ক্ষেত্রে, আপনি supplyAsyncকার্যকর করার পরে ফলাফল পেতে পদ্ধতিটি ব্যবহার করতে পারেন ।

এখানে কিছু রেফারেন্স খুঁজুন ।

    CompletableFuture<Integer> completableFuture
      = CompletableFuture.supplyAsync(() -> yourMethod());

   completableFuture.get() //gives you the value

1

উপরের উত্তরে বর্ণিত ফিউচার ব্যবহার করা কাজটি করে তবে f.get () হিসাবে কিছুটা কম উল্লেখযোগ্যভাবে থ্রেডটি ফলাফল না পাওয়া পর্যন্ত অবরুদ্ধ করে, যা সম্মতিবদ্ধতা লঙ্ঘন করে।

সেরা সমাধান হ'ল পেয়ারাটির শ্রবণযোগ্য ভবিষ্যত ব্যবহার করা। একটি উদাহরণ :

    ListenableFuture<Void> future = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1, new NamedThreadFactory).submit(new Callable<Void>()
    {
        @Override
        public Void call() throws Exception
        {
            someBackgroundTask();
        }
    });
    Futures.addCallback(future, new FutureCallback<Long>()
    {
        @Override
        public void onSuccess(Long result)
        {
            doSomething();
        }

        @Override
        public void onFailure(Throwable t)
        {

        }
    };

1

আপনার কোডে ছোট ছোট পরিবর্তন করে আপনি আরও সাধারণ উপায়ে এটি অর্জন করতে পারেন।

 final Handler responseHandler = new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                //txtView.setText((String) msg.obj);
                Toast.makeText(MainActivity.this,
                        "Result from UIHandlerThread:"+(int)msg.obj,
                        Toast.LENGTH_LONG)
                        .show();
            }
        };

        HandlerThread handlerThread = new HandlerThread("UIHandlerThread"){
            public void run(){
                Integer a = 2;
                Message msg = new Message();
                msg.obj = a;
                responseHandler.sendMessage(msg);
                System.out.println(a);
            }
        };
        handlerThread.start();

সমাধান:

  1. Handlerইউআই থ্রেডে একটি তৈরি করুন , যাকে বলা হয়responseHandler
  2. এটি ইউআই থ্রেড Handlerথেকে শুরু করুন Looper
  3. ইন HandlerThread, এই উপর বার্তা পোস্ট করুনresponseHandler
  4. handleMessgaeToastবার্তা থেকে প্রাপ্ত মান সহ একটি দেখায় । এই বার্তা অবজেক্টটি জেনেরিক এবং আপনি বিভিন্ন ধরণের বৈশিষ্ট্য প্রেরণ করতে পারেন।

এই পদ্ধতির সাহায্যে আপনি বিভিন্ন সময়ে UI থ্রেডে একাধিক মান প্রেরণ করতে পারেন। আপনি Runnableএটিতে অনেকগুলি বস্তু চালাতে (পোস্ট করতে পারেন) HandlerThreadএবং প্রতিটি বস্তুতে Runnableমান সেট Messageকরতে পারেন যা ইউআই থ্রেড দ্বারা প্রাপ্ত হতে পারে।

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