উত্তর:
wait()
এবং notify()
পদ্ধতি পর্যন্ত একটি নির্দিষ্ট শর্ত পূরণ করা হয় ব্লক করার জন্য একটি থ্রেড করার অনুমতি একটি প্রক্রিয়া প্রদান ডিজাইন করা হয়। এর জন্য আমি ধরে নিচ্ছি আপনি একটি ব্লকিং সারি প্রয়োগকরণ লিখতে চাইছেন, যেখানে আপনার কাছে কিছু নির্দিষ্ট আকারের উপাদানগুলির ব্যাকিং-স্টোর রয়েছে।
আপনাকে প্রথমে যে কাজটি করতে হবে তা হ'ল শর্তগুলি সনাক্ত করা। এই ক্ষেত্রে, আপনি put()
স্টোরে মুক্ত স্থান না পাওয়া পর্যন্ত পদ্ধতিটি অবরুদ্ধ করতে চান এবং take()
কোনও উপাদান ফিরে না আসা পর্যন্ত আপনি এই পদ্ধতিটি অবরুদ্ধ করতে চান ।
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T element) throws InterruptedException {
while(queue.size() == capacity) {
wait();
}
queue.add(element);
notify(); // notifyAll() for multiple producer/consumer threads
}
public synchronized T take() throws InterruptedException {
while(queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify(); // notifyAll() for multiple producer/consumer threads
return item;
}
}
আপনাকে যেভাবে ওয়েটটি ব্যবহার করতে হবে এবং প্রক্রিয়াগুলি অবহিত করতে হবে সে সম্পর্কে কয়েকটি বিষয় লক্ষ্যণীয়।
প্রথমত, আপনাকে নিশ্চিত করতে হবে যে কোনও কল wait()
বা notify()
কোডের একটি সিঙ্ক্রোনাইজড অঞ্চলের মধ্যে রয়েছে ( একই সাথে একই সাথে wait()
ও notify()
কলগুলি সিঙ্ক্রোনাইজ হচ্ছে)। এর কারণ (স্ট্যান্ডার্ড থ্রেড সুরক্ষা উদ্বেগ ব্যতীত) একটি মিসড সিগন্যাল হিসাবে পরিচিত এমন কোনও কারণ।
এর একটি উদাহরণ, একটি থ্রেড কল করতে পারে put()
যখন সারিটি পূর্ণ হয়ে যায় তখন এটি শর্তটি পরীক্ষা করে, দেখায় যে সারিটি পূর্ণ রয়েছে, তবে এটি অন্য থ্রেডটি নির্ধারিত হওয়ার আগেই ব্লক করতে পারে। এই দ্বিতীয় থ্রেডটি take()
সারি থেকে পাওয়া একটি উপাদান এবং অপেক্ষার থ্রেডগুলি সূচিত করে যে সারিটি আর পূর্ণ নয়। কারণ প্রথম থ্রেড ইতিমধ্যে শর্তটি পরীক্ষা করেছে তবে এটি wait()
অগ্রগতি সত্ত্বেও এটি পুনরায় নির্ধারিত হওয়ার পরে কেবল কল করবে ।
একটি ভাগ করা অবজেক্টে সিঙ্ক্রোনাইজ করে আপনি নিশ্চিত করতে পারেন যে এই সমস্যাটি ঘটে না, কারণ দ্বিতীয় থ্রেডের take()
কলটি প্রথম থ্রেডটি অবরুদ্ধ না করা পর্যন্ত অগ্রগতি করতে সক্ষম হবে না।
দ্বিতীয়ত, উদ্দীপনা জাগ্রত হিসাবে পরিচিত একটি সমস্যার কারণে আপনি যদি একটি আইটি স্টেটমেন্ট না দিয়ে কিছুক্ষণ লুপে যাচাই করছেন শর্তটি আপনার রাখা উচিত। এখানেই অপেক্ষা করা থ্রেডটি কল না করে আবার কখনও সক্রিয় করা যেতে পারে notify()
। কিছুক্ষণ লুপের মধ্যে এই চেকটি স্থাপন করা নিশ্চিত করে যে কোনও উত্সাহী জাগ্রত দেখা দিলে শর্তটি পুনরায় পরীক্ষা করা হবে এবং থ্রেডটি wait()
আবার কল করবে ।
অন্যান্য উত্তরগুলির মধ্যে যেমন উল্লেখ করা হয়েছে, জাভা 1.5 একটি নতুন সমাবর্তন গ্রন্থাগার ( java.util.concurrent
প্যাকেজে) প্রবর্তন করেছে যা অপেক্ষা / বিজ্ঞপ্তি ব্যবস্থার উপর একটি উচ্চ স্তরের বিমূর্ততা সরবরাহ করার জন্য তৈরি করা হয়েছিল। এই নতুন বৈশিষ্ট্যগুলি ব্যবহার করে, আপনি মূল উদাহরণটি আবার লিখতে পারেন:
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public void put(T element) throws InterruptedException {
lock.lock();
try {
while(queue.size() == capacity) {
notFull.await();
}
queue.add(element);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while(queue.isEmpty()) {
notEmpty.await();
}
T item = queue.remove();
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
অবশ্যই যদি আপনার যদি অবরুদ্ধ সারির প্রয়োজন হয় তবে আপনার ব্লকিংকিউ ইন্টারফেস প্রয়োগ করা উচিত ।
এছাড়াও, এই জাতীয় স্টাফগুলির জন্য আমি অনুশীলনে জাভা কনকুরেন্সির উচ্চ প্রস্তাব দিই , কারণ এটি সম্মতি সংক্রান্ত সমস্যা এবং সমাধানগুলির বিষয়ে আপনি যা জানতে চাইতে পারেন তার সমস্ত কিছুই অন্তর্ভুক্ত করে।
একটি সারি উদাহরণ নয়, তবে অত্যন্ত সহজ :)
class MyHouse {
private boolean pizzaArrived = false;
public void eatPizza(){
synchronized(this){
while(!pizzaArrived){
wait();
}
}
System.out.println("yumyum..");
}
public void pizzaGuy(){
synchronized(this){
this.pizzaArrived = true;
notifyAll();
}
}
}
কিছু গুরুত্বপূর্ণ বিষয়:
1) কখনও করবেন না
if(!pizzaArrived){
wait();
}
সর্বদা ব্যবহার (শর্ত), কারণ
while(!pizzaExists){ wait(); }
।২) অপেক্ষা / নোফটি চাওয়ার আগে আপনাকে অবশ্যই লকটি (সিঙ্ক্রোনাইজড) রাখতে হবে। জাগ্রত হওয়ার আগে থ্রেডগুলিও লক অর্জন করতে হয়।
3) আপনার সিঙ্ক্রোনাইজড ব্লকের মধ্যে কোনও লক অর্জন এড়ানোর চেষ্টা করুন এবং ভিনগ্রহী পদ্ধতিগুলি (যে পদ্ধতিগুলি আপনি কী জানেন তারা কী করছেন তা নিশ্চিতভাবে জানেন না) না চালানোর চেষ্টা করুন। আপনার যদি তা করতে হয় তবে ডেডলকগুলি এড়াতে ব্যবস্থা নেওয়ার বিষয়টি নিশ্চিত করুন।
4) বিজ্ঞপ্তি () সাথে সতর্কতা অবলম্বন করুন। আপনি কী করছেন তা না জানা পর্যন্ত notifyAll () এর সাথে লেগে থাকুন।
5) সর্বশেষ, তবে কম নয়, অনুশীলনে জাভা কনকুরেন্সি পড়ুন !
pizzaArrived
পতাকা ব্যবহার করছেন কেন ? পতাকাটি যদি কোনও কল ছাড়াই পরিবর্তন notify
করা হয় তবে এর কোনও প্রভাব থাকবে না। এছাড়াও কেবল উদাহরণ দিয়ে কাজ করে wait
এবং notify
কল করে।
synchronized
কীওয়ার্ড দ্বারা সুরক্ষিত থাকে, তখন ভেরিয়েবলটি ঘোষণা করা volatile
বাড়াবাড়ি হয় এবং বিভ্রান্তি এড়াতে এড়াতে বাঞ্ছনীয় @ মিরিদা
যদিও আপনি চেয়েছিলেন wait()
এবংnotify()
বিশেষভাবে আমার কাছে মনে হয়েছে যে এই উদ্ধৃতিটি এখনও যথেষ্ট গুরুত্বপূর্ণ:
জোশ ব্লচ, কার্যকর জাভা 2 য় সংস্করণ , আইটেম 69: সম্মতিযুক্ত ইউটিলিটিগুলিতে পছন্দ করুন wait
এবং notify
(তার উপর জোর দিন):
ব্যবহার করতে
wait
এবংnotify
সঠিকভাবে অসুবিধা দেওয়া , আপনার পরিবর্তে উচ্চ স্তরের সম্মিলিত ইউটিলিটিগুলি ব্যবহার করা উচিত [...] ব্যবহার করাwait
এবংnotify
সরাসরি প্রদত্ত উচ্চ-স্তরের ভাষার তুলনায় "কনক্যুরঞ্জি এসেম্বলি ল্যাঙ্গুয়েজে" প্রোগ্রামিংয়ের মতোjava.util.concurrent
। খুব কমই ব্যবহৃত হয়, যদি কখনও হয় তবে ব্যবহার করার কারণwait
এবংnotify
নতুন কোডে ।
notify()
এবং wait()
আবার
আপনি এই জাভা টিউটোরিয়ালটি একবার দেখেছেন ?
আরও, আমি আপনাকে সত্যিকারের সফ্টওয়্যারটিতে এই ধরণের স্টাফ নিয়ে খেলতে দূরে রাখতে পরামর্শ দেব। এটি খেলতে ভাল তাই আপনি কী তা জানেন তা তবে এটির সমস্ত জায়গায় সমাবর্তনে সমস্যা রয়েছে। আপনি যদি অন্য লোকের জন্য সফ্টওয়্যার তৈরি করে থাকেন তবে উচ্চ স্তরের বিমূর্ততা এবং সিঙ্ক্রোনাইজড সংগ্রহ বা জেএমএস সারি ব্যবহার করা ভাল।
এটা আমি অন্তত কি করি। আমি কোনও সহকর্মী বিশেষজ্ঞ নই তাই আমি যেখানেই সম্ভব হাতের থ্রেড পরিচালনা করা থেকে দূরে থাকি।
উদাহরণ
public class myThread extends Thread{
@override
public void run(){
while(true){
threadCondWait();// Circle waiting...
//bla bla bla bla
}
}
public synchronized void threadCondWait(){
while(myCondition){
wait();//Comminucate with notify()
}
}
}
public class myAnotherThread extends Thread{
@override
public void run(){
//Bla Bla bla
notify();//Trigger wait() Next Step
}
}
থ্রেডিংয়ে অপেক্ষা () এবং বিজ্ঞপ্তি () এর উদাহরণ।
একটি সিঙ্ক্রোনাইজড স্ট্যাটিক অ্যারে তালিকাটি রিসোর্স হিসাবে ব্যবহৃত হয় এবং অ্যারের তালিকাটি ফাঁকা থাকলে অপেক্ষা () পদ্ধতিটি বলা হয়। অ্যারে তালিকার জন্য কোনও উপাদান যুক্ত হয়ে গেলে सूचित করুন () পদ্ধতিটি চালু করা হয়।
public class PrinterResource extends Thread{
//resource
public static List<String> arrayList = new ArrayList<String>();
public void addElement(String a){
//System.out.println("Add element method "+this.getName());
synchronized (arrayList) {
arrayList.add(a);
arrayList.notifyAll();
}
}
public void removeElement(){
//System.out.println("Remove element method "+this.getName());
synchronized (arrayList) {
if(arrayList.size() == 0){
try {
arrayList.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
arrayList.remove(0);
}
}
}
public void run(){
System.out.println("Thread name -- "+this.getName());
if(!this.getName().equalsIgnoreCase("p4")){
this.removeElement();
}
this.addElement("threads");
}
public static void main(String[] args) {
PrinterResource p1 = new PrinterResource();
p1.setName("p1");
p1.start();
PrinterResource p2 = new PrinterResource();
p2.setName("p2");
p2.start();
PrinterResource p3 = new PrinterResource();
p3.setName("p3");
p3.start();
PrinterResource p4 = new PrinterResource();
p4.setName("p4");
p4.start();
try{
p1.join();
p2.join();
p3.join();
p4.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Final size of arraylist "+arrayList.size());
}
}
if(arrayList.size() == 0)
, আমি মনে করি এটি এখানে ভুল হতে পারে।
notify
কেবল একটি সুতো জোগায় । দুটি গ্রাহক থ্রেড যদি কোনও উপাদানটি সরানোর জন্য প্রতিযোগিতা করে থাকে তবে একটি বিজ্ঞপ্তি অন্য গ্রাহক থ্রেডকে জাগ্রত করতে পারে যা এ সম্পর্কে কিছুই করতে পারে না এবং ঘুমাতে ফিরে যাবে (প্রযোজকের পরিবর্তে, আমরা আশা করছিলাম যে কোনও নতুন উপাদান সন্নিবেশ করানো হবে।) কারণ প্রযোজক থ্রেড জাগ্রত হয় না, কিছুই sertedোকানো হয় না এবং এখন তিনটি থ্রেড অনির্দিষ্ট সময়ের জন্য ঘুমাবে। আমি আমার পূর্ববর্তী মন্তব্যটি সরিয়ে দিয়েছি কারণ এটি (ভুলভাবে) বলেছিল যে