কীভাবে একটি জাভা থ্রেড অন্য থ্রেডের আউটপুটটির জন্য অপেক্ষা করবেন?


128

আমি একটি অ্যাপ্লিকেশন-লজিক-থ্রেড এবং একটি ডাটাবেস-অ্যাক্সেস-থ্রেড সহ একটি জাভা অ্যাপ্লিকেশন তৈরি করছি। এগুলির উভয়ই আবেদনের পুরো জীবনকালের জন্য অব্যাহত রয়েছে এবং উভয়কে একই সময়ে চলতে হবে (একটি সার্ভারের সাথে কথা বলে, একটি ব্যবহারকারীর সাথে কথা বলে; যখন অ্যাপটি সম্পূর্ণভাবে শুরু হয়, তখন আমার দু'জনেরই কাজ করা প্রয়োজন)।

যাইহোক, শুরুতে, আমার নিশ্চিত করা দরকার যে প্রাথমিকভাবে অ্যাপ থ্রেডটি ডিবি থ্রেড প্রস্তুত না হওয়া পর্যন্ত অপেক্ষা করে (বর্তমানে একটি কাস্টম পদ্ধতিতে পোলিং দ্বারা নির্ধারিত dbthread.isReady())। ডিবি থ্রেড প্রস্তুত না হওয়া পর্যন্ত অ্যাপ থ্রেডটি ব্লক করে দিলে আমি আপত্তি করব না।

Thread.join() সমাধানের মতো দেখায় না - ডিবি থ্রেডটি কেবল অ্যাপের শাটডাউন থেকে প্রস্থান করে।

while (!dbthread.isReady()) {} ধরণের কাজ, তবে খালি লুপটি প্রচুর প্রসেসরের চক্র গ্রহণ করে।

অন্য কোন ধারণা? ধন্যবাদ।

উত্তর:


128

আমি সত্যিই আপনাকে সুপারিশ করব যে আপনি মাল্টিথ্রেডিংয়ের যাদুকরী জগতে আরম্ভ করার আগে আপনি সূর্যের জাভা কনকুরেন্সির মতো টিউটোরিয়ালটি ব্যবহার করুন ।

বেশ কয়েকটি ভাল বইও বেরিয়েছে ("জাভায় কনক্যান্ট প্রোগ্রামিং", "অনুশীলনে জাভা কনকুরেন্সি" এর জন্য গুগল।

আপনার উত্তর পেতে:

আপনার কোডটিতে অবশ্যই অপেক্ষা করা dbThreadউচিত, আপনার অবশ্যই এর মতো কিছু থাকতে হবে:

//do some work
synchronized(objectYouNeedToLockOn){
    while (!dbThread.isReady()){
        objectYouNeedToLockOn.wait();
    }
}
//continue with work after dbThread is ready

আপনার dbThreadপদ্ধতিতে, আপনাকে এই জাতীয় কিছু করতে হবে:

//do db work
synchronized(objectYouNeedToLockOn){
    //set ready flag to true (so isReady returns true)
    ready = true;
    objectYouNeedToLockOn.notifyAll();
}
//end thread run method here

objectYouNeedToLockOnআমি এই উদাহরণ মধ্যে ব্যবহার করছি বাঞ্ছনীয় বস্তু আপনি প্রতিটি থ্রেড থেকে একই সময়ে নিপূণভাবে প্রয়োজন, অথবা আপনি একটি পৃথক তৈরী করতে পারে Object(আমি পদ্ধতি নিজেদের সিঙ্ক্রোনাইজ উপার্জন না করার পরামর্শ দিচ্ছি) যে উদ্দেশ্যে:

private final Object lock = new Object();
//now use lock in your synchronized blocks

আপনার বোঝাপড়াটি আরও বাড়ানোর জন্য:
উপরোক্ত কিছু অন্যান্য উপায় (মাঝে মাঝে আরও ভাল) রয়েছে যেমন CountdownLatches, ইত্যাদি ইত্যাদি Java জাভা ৫ থেকে java.util.concurrentপ্যাকেজ এবং সাব-প্যাকেজগুলিতে অনেকগুলি নিফটি কনসুরেন্সির ক্লাস রয়েছে । সম্মতি জানার জন্য, বা একটি ভাল বই পাওয়ার জন্য আপনাকে সত্যই অনলাইনে উপাদানগুলি সন্ধান করতে হবে।


আমি ভুল না হলে সমস্ত থ্রেড কোডও অবজেক্টগুলিতে খুব সুন্দরভাবে সংহত করা যায়। সুতরাং আমি মনে করি না যে এই থ্রেড সম্পর্কিত কাজটি কার্যকর করার জন্য অবজেক্ট সিঙ্ক্রোনাইজেশন ব্যবহার করা ভাল উপায়।
ব্যবহারকারী 1914692

@ ব্যবহারকারী1914692: উপরোক্ত পদ্ধতির ব্যবহারে কোন অসুবিধা রয়েছে তা নিশ্চিত নন - আরও ব্যাখ্যা করার জন্য যত্নশীল?
পিসকভোর

1
@ পিসকোভার: দুঃখিত আমি এটি অনেক আগে লিখেছিলাম এবং আমার মনে যা ছিল তা আমি প্রায় ভুলে গেছি। সম্ভবত আমি কেবল অবজেক্ট সিঙ্ক্রোনাইজেশনের পরিবর্তে লকটি ব্যবহার করা আরও ভাল বোঝাতে চাইছি, পূর্ববর্তীটি পূর্বের এক সরলীকৃত রূপ।
ব্যবহারকারী 1914692

আমি বুঝতে পারি না এটি কীভাবে কাজ করে। থ্রেড যদি aঅবজেক্টে অপেক্ষা করে থাকে তবে synchronised(object)অন্য থ্রেডটি synchronized(object)কল করতে কীভাবে যেতে পারে object.notifyAll()? আমার প্রোগ্রামে, সমস্ত কিছু কেবল আটকে গেছে synchronozed
টোমা জ্যাটো - মনিকা

@ টম্যাজাটো প্রথম থ্রেডকে object.wait()কার্যকরভাবে সেই বস্তুর লকটি আনলক করার আহ্বান জানায় । যখন দ্বিতীয় থ্রেডটি তার সিঙ্ক্রোনাইজড ব্লকটি "প্রস্থান" করে, তখন অন্যান্য বস্তুগুলি waitপদ্ধতি থেকে প্রকাশিত হয় এবং সেই সময়ে লকটি পুনরায় প্রাপ্ত করে।
রজারডপ্যাক

140

1 এর কাউন্টার সহ একটি কাউন্টডাউনল্যাচ ব্যবহার করুন ।

CountDownLatch latch = new CountDownLatch(1);

এখন অ্যাপ্লিকেশন থ্রেডে করুন-

latch.await();

ডিবি থ্রেডে, আপনার হয়ে যাওয়ার পরে, করুন -

latch.countDown();

4
এটির সরলতার জন্য আমি সমাধানটি সত্যিই পছন্দ করি, যদিও কোডটির অর্থ প্রথম দর্শনে বোঝা শক্ত হতে পারে।
প্রাণঘাতী-গিটার

3
এই ব্যবহারটির জন্য আপনার ল্যাচটি ব্যবহার হয়ে গেলে পুনরায় তৈরি করা প্রয়োজন। উইন্ডোজে একটি Waitable ইভেন্ট অনুরূপ ব্যবহার পেতে, আপনি একটি BooleanLatch, অথবা একটি পুনরায় সেটযোগ্য CountDownLatch চেষ্টা করা উচিত: docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/... stackoverflow.com/questions / 6595835 /…
ফায়াত

1
হাই, আমি যদি প্রথম কোনও অ্যাসিঙ্ক পদ্ধতিতে কল করি যে এটি কোনও ঘটনাকে আগুন দেওয়ার মতো বলে মনে করে: 1) asyncFunc (); 2) ল্যাচ.ওয়ায়েট (); তারপরে ইভেন্টটি হ্যান্ডলিংয়ের ফাংশনটিতে এটি পাওয়ার পরে আমি কাউন্টডাউন করি। ল্যাচ.ওয়ায়েট () বলা হওয়ার আগে ইভেন্টটি পরিচালনা করা হবে না তা আমি কীভাবে নিশ্চিত করতে পারি? আমি 1 এবং 2 লাইনের মধ্যে প্রিম্পশন আটকাতে চাই Thank ধন্যবাদ
NioX5199

1
ত্রুটির ক্ষেত্রে চিরকাল অপেক্ষা করা এড়াতে, countDown()একটি finally{}ব্লকে রেখে দিন
ড্যানিয়েল অ্যাল্ডার

23

প্রয়োজনীয়তা ::

  1. পূর্ববর্তী শেষ হওয়া পর্যন্ত পরবর্তী থ্রেডের সম্পাদনের জন্য অপেক্ষা করা To
  2. পরবর্তী থ্রেডটি অবশ্যই সময় ব্যয় নির্বিশেষে পূর্ববর্তী থ্রেডটি বন্ধ না হওয়া পর্যন্ত শুরু করা উচিত।
  3. এটি অবশ্যই সহজ এবং ব্যবহারযোগ্য।

উত্তর ::

@ Java.util.concurrent.Future.get () ডক দেখুন

ভবিষ্যতে.গেট () গণনাটি সম্পূর্ণ হওয়ার জন্য অপেক্ষা করা হয় এবং তার ফলাফল পুনরুদ্ধার করে।

কাজ শেষ!! নীচে উদাহরণ দেখুন

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.junit.Test;

public class ThreadTest {

    public void print(String m) {
        System.out.println(m);
    }

    public class One implements Callable<Integer> {

        public Integer call() throws Exception {
            print("One...");
            Thread.sleep(6000);
            print("One!!");
            return 100;
        }
    }

    public class Two implements Callable<String> {

        public String call() throws Exception {
            print("Two...");
            Thread.sleep(1000);
            print("Two!!");
            return "Done";
        }
    }

    public class Three implements Callable<Boolean> {

        public Boolean call() throws Exception {
            print("Three...");
            Thread.sleep(2000);
            print("Three!!");
            return true;
        }
    }

    /**
     * @See java.util.concurrent.Future.get() doc
     *      <p>
     *      Waits if necessary for the computation to complete, and then
     *      retrieves its result.
     */
    @Test
    public void poolRun() throws InterruptedException, ExecutionException {
        int n = 3;
        // Build a fixed number of thread pool
        ExecutorService pool = Executors.newFixedThreadPool(n);
        // Wait until One finishes it's task.
        pool.submit(new One()).get();
        // Wait until Two finishes it's task.
        pool.submit(new Two()).get();
        // Wait until Three finishes it's task.
        pool.submit(new Three()).get();
        pool.shutdown();
    }
}

এই প্রোগ্রামটির আউটপুট ::

One...
One!!
Two...
Two!!
Three...
Three!!

আপনি দেখতে পাচ্ছেন যে এটির কাজ শেষ করার আগে 6 সেকেন্ড লাগে যা অন্য থ্রেডের চেয়ে বড়। সুতরাং ফিউচার.জেট () টাস্কটি সম্পন্ন না হওয়া পর্যন্ত অপেক্ষা করে।

যদি আপনি مستقبل.get () ব্যবহার না করেন তবে এটি সমাপ্ত হতে অপেক্ষা করে না এবং ভিত্তিক সময় খরচ চালায়।

জাভা সম্মতি সঙ্গে শুভকামনা।


আপনার উত্তর করার জন্য আপনাকে ধন্যবাদ! আমি CountdownLatchএস ব্যবহার করেছি , তবে আপনার এটি অনেক বেশি নমনীয় পদ্ধতি।
পিসকোভর

9

অনেকগুলি সঠিক উত্তর কিন্তু একটি সাধারণ উদাহরণ ছাড়াই .. কীভাবে ব্যবহার করবেন এটি এখানে একটি সহজ এবং সহজ উপায় CountDownLatch:

//inside your currentThread.. lets call it Thread_Main
//1
final CountDownLatch latch = new CountDownLatch(1);

//2
// launch thread#2
new Thread(new Runnable() {
    @Override
    public void run() {
        //4
        //do your logic here in thread#2

        //then release the lock
        //5
        latch.countDown();
    }
}).start();

try {
    //3 this method will block the thread of latch untill its released later from thread#2
    latch.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}

//6
// You reach here after  latch.countDown() is called from thread#2

8
public class ThreadEvent {

    private final Object lock = new Object();

    public void signal() {
        synchronized (lock) {
            lock.notify();
        }
    }

    public void await() throws InterruptedException {
        synchronized (lock) {
            lock.wait();
        }
    }
}

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

একটি থ্রেড ইভেন্ট তৈরি করুন:

ThreadEvent resultsReady = new ThreadEvent();

পদ্ধতিতে এটি ফলাফলের জন্য অপেক্ষা করছে:

resultsReady.await();

এবং সমস্ত ফলাফল তৈরির পরে ফলাফলটি তৈরি করার পদ্ধতিটিতে:

resultsReady.signal();

সম্পাদনা করুন:

(এই পোস্টটি সম্পাদনা করার জন্য দুঃখিত, তবে এই কোডটির খুব খারাপ দৌড় অবস্থা এবং মন্তব্য করার মতো যথেষ্ট খ্যাতি আমার নেই)

আপনি কেবল এটি ব্যবহার করতে পারেন যদি আপনি 100% নিশ্চিত হন যে (সিগন্যালটি) অপেক্ষা করা হবে () এর পরে ডাকা হবে। আপনি জাভা অবজেক্ট যেমন যেমন উইন্ডোজ ইভেন্টস ব্যবহার করতে পারবেন না কেন এটিই একটি বড় কারণ।

কোডটি যদি এই ক্রমে চলে:

Thread 1: resultsReady.signal();
Thread 2: resultsReady.await();

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

দ্রষ্টব্য: বেশিরভাগ সময় আপনার বিজ্ঞপ্তি () ব্যবহার করা উচিত তবে এটি উপরে "চিরকাল অপেক্ষা করুন" সমস্যার সাথে প্রাসঙ্গিক নয়।


7

প্যাকেজটির বাইরে কাউন্টডাউনল্যাচ ক্লাস চেষ্টা করুন java.util.concurrentযা উচ্চ স্তরের সিঙ্ক্রোনাইজেশন প্রক্রিয়া সরবরাহ করে যা নিম্ন স্তরের স্টাফের তুলনায় অনেক কম ত্রুটিযুক্ত।


6

আপনি দুটি থ্রেডের মধ্যে ভাগ করা এক্সচেঞ্জার অবজেক্টটি ব্যবহার করে এটি করতে পারেন :

private Exchanger<String> myDataExchanger = new Exchanger<String>();

// Wait for thread's output
String data;
try {
  data = myDataExchanger.exchange("");
} catch (InterruptedException e1) {
  // Handle Exceptions
}

এবং দ্বিতীয় থ্রেডে:

try {
    myDataExchanger.exchange(data)
} catch (InterruptedException e) {

}

অন্যরা যেমন বলেছে, এই হালকা-হৃদয়যুক্ত এবং কেবল অনুলিপি-পেস্ট কোডটি গ্রহণ করবেন না। প্রথমে কিছু পড়ুন।


4

ভবিষ্যত থেকে ইন্টারফেস java.lang.concurrentপ্যাকেজ অন্য থ্রেড গণনাকৃত ফলাফল অ্যাক্সেস প্রদান ডিজাইন করা হয়েছে।

এই ধরণের কাজ করার জন্য তৈরি উপায়ের জন্য ফিউচারটাস্ক এবং এক্সিকিউটারসেবা দেখুন at

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


2

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

while (!dbthread.isReady()) {
  Thread.sleep(250);
}

আপনি মার্জিত কোড কল করতে পারে এমন খুব কমই, তবে কাজটি হয়ে যায়।

আপনি যদি ডাটাবেস কোডটি সংশোধন করতে পারেন, তবে অন্য উত্তরে প্রস্তাবিত হিসাবে একটি মিটেক্স ব্যবহার করা ভাল।


3
এটি বেশ ব্যস্ততা কেবল অপেক্ষা করার জন্য। জাভা 5 এর ব্যবহারকারীর কনট্রাক্ট প্যাকেজগুলি থেকে কনস্ট্রাক্ট ব্যবহার করা যেতে হবে। stackoverflow.com/questions/289434/… আমার কাছে আপাতত সেরা সমাধান হিসাবে দেখায়।
কেম ক্যাটিকাস

এটি অপেক্ষা করতে ব্যস্ত, তবে যদি কেবলমাত্র এই নির্দিষ্ট জায়গায় এটি প্রয়োজনীয় হয় এবং ডিবি লাইব্রেরিতে যদি অ্যাক্সেস না থাকে তবে আপনি আর কী করতে পারেন? ব্যস্ত অপেক্ষা অপরিহার্যভাবে খারাপ নয়
মারিও অর্টেগেন

2

এটি সমস্ত ভাষায় প্রযোজ্য:

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

আপনার পরিস্থিতি অচলাবস্থার অন্যতম সাধারণ কারণ- নিশ্চিত হয়ে নিন যে ত্রুটি ঘটেছে তা বিবেচনা না করেই আপনি অন্য থ্রেডকে সিগন্যাল করেছেন। উদাহরণ- যদি আপনার অ্যাপ্লিকেশন ব্যতিক্রম ছুঁড়ে ফেলে- এবং কখনও কখনও পদ্ধতিটি কল করে না যে জিনিসগুলি সম্পূর্ণ হয়ে গেছে signal এটি এটি তৈরি করবে যাতে অন্য থ্রেড কখনই 'জেগে ওঠে না'।

আমি আপনাকে পরামর্শ দিচ্ছি যে আপনার ঘটনা প্রয়োগের আগে এই দৃষ্টান্তটি আরও ভাল করে বুঝতে ইভেন্ট এবং ইভেন্ট হ্যান্ডলারগুলি ব্যবহার করার ধারণাগুলি সন্ধান করুন।

বিকল্পভাবে আপনি একটি মিউটেক্স ব্যবহার করে একটি ব্লকিং ফাংশন কল ব্যবহার করতে পারেন- যার ফলে থ্রেডটি সম্পদ মুক্ত হওয়ার জন্য অপেক্ষা করবে। এটি করার জন্য আপনার ভাল থ্রেড সিঙ্ক্রোনাইজেশন প্রয়োজন - যেমন:

Thread-A Locks lock-a
Run thread-B
Thread-B waits for lock-a
Thread-A unlocks lock-a (causing Thread-B to continue)
Thread-A waits for lock-b 
Thread-B completes and unlocks lock-b

2

আপনি একটি থ্রেডে একটি ব্লক করা সারি থেকে পড়তে পারেন এবং এটিতে অন্য থ্রেডে লিখতে পারেন।


1

থেকে

  1. join() উড়িয়ে দেওয়া হয়েছে
  2. আপনি ইতিমধ্যে কাউন্টডাউনল্যাচ এবং ব্যবহার করেছেন
  3. ফিউচার.জেট () ইতিমধ্যে অন্যান্য বিশেষজ্ঞদের দ্বারা প্রস্তাবিত,

আপনি অন্যান্য বিকল্প বিবেচনা করতে পারেন:

  1. সমস্ত থেকেExecutorService

    invokeAll(Collection<? extends Callable<T>> tasks)

    প্রদত্ত টাস্কগুলি কার্যকর করে ফিউচারগুলির একটি তালিকা ফিরিয়ে তাদের স্ট্যাটাস এবং ফলাফলগুলি সম্পূর্ণ হয়ে গেলে।

  2. ফোরজজাইনপুল বা নিউ ওয়ার্ক স্টিলিংপুলExecutors (জাভা 8 প্রকাশের পর থেকে )

    সমস্ত উপলভ্য প্রসেসরকে তার লক্ষ্য সমান্তরালতা স্তর হিসাবে ব্যবহার করে একটি ওয়ার্ক-স্টিলিং থ্রেড পুল তৈরি করে।


-1

এখানে চিত্র বর্ণনা লিখুন

এই ধারণা প্রয়োগ করতে পারেন ?. আপনি যদি কাউন্টডাউনলেটস বা সেমোফোর্স ব্যবহার করেন তবে নিখুঁত কাজ করে তবে আপনি যদি কোনও সাক্ষাত্কারের সবচেয়ে সহজ উত্তরটি খুঁজছেন তবে আমি মনে করি এটি প্রয়োগ হতে পারে।


1
এটি একটি সাক্ষাত্কারের জন্য ঠিক আছে তবে প্রকৃত কোডের জন্য নয়?
পিসকভোর

কারণ এক্ষেত্রে ক্রমান্বয়ে চলছে একজনের অপর অপেক্ষার জন্য। সেরা সমাধানটি সেমোফোর্স ব্যবহার করা হতে পারে কারণ এখানে দেওয়া উত্তম উত্তর হ'ল কাউন্টডাউনল্যাচগুলি থ্রেড কখনই ঘুমায় না যার অর্থ সিপিইউ চক্রের ব্যবহার।
ফ্রাঙ্কো

তবে বিন্দুটি "এগুলি ধারাবাহিকভাবে চালানো হয়নি"। এই প্রশ্নটি আরও পরিষ্কার করার জন্য আমি প্রশ্নটি সম্পাদনা করব: ডাটাবেস প্রস্তুত না হওয়া পর্যন্ত জিইউআই থ্রেড অপেক্ষা করে এবং তারপরে উভয়ই অ্যাপ্লিকেশনটির বাকি অংশের জন্য একযোগে চালিত হয় : জিইউআই থ্রেড ডিবি থ্রেডকে আদেশ পাঠায় এবং ফলাফলগুলি পড়ে। (এবং আবারও: কোডের বিন্দুটি কী যা কোন সাক্ষাত্কারে ব্যবহার করা যেতে পারে তবে প্রকৃত কোডে নয়? আমার দেখা বেশিরভাগ প্রযুক্তিগত সাক্ষাত্কারের কোডের পটভূমি ছিল এবং একই প্রশ্নটি জিজ্ঞাসা করত; এছাড়াও সত্যিকারের অ্যাপের জন্য আমার এই জিনিসটির প্রয়োজন ছিল আমি তখন লিখছিলাম, হোম
ওয়ার্কের

1
So. এটি একটি উত্পাদক গ্রাহক সমস্যা যা semaphores ব্যবহার করে। আমি একটি উদাহরণ দেওয়ার চেষ্টা করব
ফ্রেঞ্চো

আমি github.com/francoj22/SemProducerConsumer/blob/master/src/com/… একটি প্রকল্প তৈরি করেছি । এটা ঠিক কাজ করে।
ফ্রাঙ্কো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.