ভূমিকা
থ্রেড একটি আকর্ষণীয় জিনিস. অতীতের পর্যালোচনাগুলিতে, আমরা মাল্টিথ্রেডিং বাস্তবায়নের জন্য উপলব্ধ কিছু সরঞ্জামগুলি দেখেছি। দেখা যাক অন্যান্য আকর্ষণীয় জিনিস আমরা কি করতে পারি। এই মুহুর্তে, আমরা অনেক কিছু জানি। উদাহরণস্বরূপ, "
বেটার একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট I — থ্রেডস অফ এক্সিকিউশন " থেকে, আমরা জানি যে থ্রেড ক্লাস এক্সিকিউশনের একটি থ্রেড উপস্থাপন করে। আমরা জানি যে একটি থ্রেড কিছু কাজ করে। আমরা যদি আমাদের কাজগুলি করতে সক্ষম হতে চাই
run
, তাহলে আমাদের অবশ্যই থ্রেডটি দিয়ে চিহ্নিত করতে হবে
Runnable
।
![একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট VI — আগুন দূরে! - ১]()
মনে রাখার জন্য, আমরা
Tutorialspoint Online Java Compiler ব্যবহার করতে পারি :
public static void main(String[] args){
Runnable task = () -> {
Thread thread = Thread.currentThread();
System.out.println("Hello from " + thread.getName());
};
Thread thread = new Thread(task);
thread.start();
}
আমরা এটাও জানি যে আমাদের তালা বলে কিছু আছে। আমরা এই সম্পর্কে শিখেছি "
বেটার একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট II — সিঙ্ক্রোনাইজেশন । যদি একটি থ্রেড একটি লক অর্জন করে, তাহলে অন্য একটি থ্রেড লকটি অর্জন করার চেষ্টা করে লকটি প্রকাশের জন্য অপেক্ষা করতে বাধ্য হবে:
import java.util.concurrent.locks.*;
public class HelloWorld{
public static void main(String []args){
Lock lock = new ReentrantLock();
Runnable task = () -> {
lock.lock();
Thread thread = Thread.currentThread();
System.out.println("Hello from " + thread.getName());
lock.unlock();
};
Thread thread = new Thread(task);
thread.start();
}
}
আমি মনে করি যে আমরা কী করতে পারি তা নিয়ে কথা বলার সময় এসেছে।
সেমাফোরস
একসাথে কতগুলি থ্রেড চলতে পারে তা নিয়ন্ত্রণ করার সবচেয়ে সহজ উপায় হল সেমাফোর। এটা একটা রেল সিগন্যালের মত। সবুজ মানে এগিয়ে যাওয়া। লাল মানে অপেক্ষা। সেমাফোর থেকে কিসের জন্য অপেক্ষা করবেন? অ্যাক্সেস অ্যাক্সেস পেতে, আমাদের অবশ্যই এটি অর্জন করতে হবে। এবং যখন অ্যাক্সেসের আর প্রয়োজন নেই, তখন আমাদের অবশ্যই এটি ছেড়ে দিতে হবে বা ছেড়ে দিতে হবে। দেখা যাক কিভাবে এই কাজ করে. আমাদের ক্লাস আমদানি করতে হবে
java.util.concurrent.Semaphore
। উদাহরণ:
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(0);
Runnable task = () -> {
try {
semaphore.acquire();
System.out.println("Finished");
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(task).start();
Thread.sleep(5000);
semaphore.release(1);
}
আপনি দেখতে পাচ্ছেন, এই অপারেশনগুলি (অধিগ্রহণ এবং প্রকাশ) আমাদের বুঝতে সাহায্য করে কিভাবে একটি সেমাফোর কাজ করে। সবচেয়ে গুরুত্বপূর্ণ বিষয় হল যদি আমরা অ্যাক্সেস পেতে পারি, তাহলে সেমাফোরের অবশ্যই একটি ইতিবাচক সংখ্যক পারমিট থাকতে হবে। এই গণনাটি একটি ঋণাত্মক সংখ্যায় শুরু করা যেতে পারে। এবং আমরা 1টির বেশি পারমিটের অনুরোধ (অধিগ্রহণ) করতে পারি।
কাউন্টডাউনল্যাচ
পরবর্তী মেকানিজম হল
CountDownLatch
। আশ্চর্যজনকভাবে, এটি একটি গণনা সহ একটি ল্যাচ। এখানে আমাদের ক্লাসের জন্য উপযুক্ত আমদানি বিবৃতি প্রয়োজন
java.util.concurrent.CountDownLatch
। এটা একটা পায়ের দৌড়ের মত, যেখানে সবাই শুরুর লাইনে জড়ো হয়। এবং একবার সবাই প্রস্তুত হয়ে গেলে, সবাই একই সময়ে শুরুর সংকেত পায় এবং একই সাথে শুরু হয়। উদাহরণ:
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
Runnable task = () -> {
try {
countDownLatch.countDown();
System.out.println("Countdown: " + countDownLatch.getCount());
countDownLatch.await();
System.out.println("Finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
};
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
প্রথমত, আমরা প্রথমে ল্যাচকে বলি
countDown()
। গুগল কাউন্টডাউনকে "শূন্যের বিপরীত ক্রমে সংখ্যা গণনার একটি কাজ" হিসাবে সংজ্ঞায়িত করে। এবং তারপর আমরা ল্যাচকে বলি
await()
, অর্থাৎ কাউন্টারটি শূন্য না হওয়া পর্যন্ত অপেক্ষা করুন। মজার ব্যাপার হল, এটি এককালীন কাউন্টার। জাভা ডকুমেন্টেশন বলে, "যখন থ্রেডগুলিকে বারবার এইভাবে গণনা করতে হবে, পরিবর্তে একটি সাইক্লিকব্যারিয়ার ব্যবহার করুন"। অন্য কথায়, আপনার যদি পুনঃব্যবহারযোগ্য কাউন্টারের প্রয়োজন হয় তবে আপনার একটি ভিন্ন বিকল্পের প্রয়োজন
CyclicBarrier
:
সাইক্লিক ব্যারিয়ার
নামটি বোঝায়,
CyclicBarrier
এটি একটি "পুনরায় ব্যবহারযোগ্য" বাধা। আমরা ক্লাস আমদানি করতে হবে
java.util.concurrent.CyclicBarrier
. আসুন একটি উদাহরণ দেখি:
public static void main(String[] args) throws InterruptedException {
Runnable action = () -> System.out.println("On your mark!");
CyclicBarrier barrier = new CyclicBarrier(3, action);
Runnable task = () -> {
try {
barrier.await();
System.out.println("Finished");
} catch (BrokenBarrierException | InterruptedException e) {
e.printStackTrace();
}
};
System.out.println("Limit: " + barrier.getParties());
for (int i = 0; i < 3; i++) {
new Thread(task).start();
}
}
আপনি দেখতে পাচ্ছেন, থ্রেড
await
পদ্ধতিটি চালায়, অর্থাৎ এটি অপেক্ষা করে। এই ক্ষেত্রে, বাধা মান হ্রাস পায়।
barrier.isBroken()
কাউন্টডাউন শূন্যে পৌঁছে গেলে বাধাটি ভাঙা ( ) বলে বিবেচিত হয় । বাধা রিসেট করার জন্য, আপনাকে
reset()
পদ্ধতিটি কল করতে হবে, যা
CountDownLatch
নেই।
বিনিময়কারী
পরবর্তী প্রক্রিয়া হল এক্সচেঞ্জার। এই প্রসঙ্গে, একটি এক্সচেঞ্জ হল একটি সিঙ্ক্রোনাইজেশন পয়েন্ট যেখানে জিনিসগুলি পরিবর্তন বা অদলবদল করা হয়। আপনি যেমনটি আশা করবেন, একটি
Exchanger
এমন একটি শ্রেণী যা একটি বিনিময় বা অদলবদল করে। আসুন সহজ উদাহরণটি দেখি:
public static void main(String[] args) {
Exchanger<String> exchanger = new Exchanger<>();
Runnable task = () -> {
try {
Thread thread = Thread.currentThread();
String withThreadName = exchanger.exchange(thread.getName());
System.out.println(thread.getName() + " exchanged with " + withThreadName);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(task).start();
new Thread(task).start();
}
এখানে আমরা দুটি থ্রেড শুরু করি। তাদের প্রত্যেকে বিনিময় পদ্ধতি চালায় এবং অন্য থ্রেডের বিনিময় পদ্ধতিটি চালানোর জন্য অপেক্ষা করে। এটি করার সময়, থ্রেডগুলি পাস করা আর্গুমেন্টগুলি বিনিময় করে। মজাদার. এটা কি আপনাকে কিছু মনে করিয়ে দেয় না? এটা মনে করিয়ে দেয়
SynchronousQueue
, যা এর হৃদয়ে রয়েছে
CachedThreadPool
। স্পষ্টতার জন্য, এখানে একটি উদাহরণ:
public static void main(String[] args) throws InterruptedException {
SynchronousQueue<String> queue = new SynchronousQueue<>();
Runnable task = () -> {
try {
System.out.println(queue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
};
new Thread(task).start();
queue.put("Message");
}
উদাহরণ দেখায় যে যখন একটি নতুন থ্রেড শুরু হয়, এটি অপেক্ষা করবে, কারণ সারিটি খালি থাকবে। এবং তারপর প্রধান থ্রেড সারিতে "বার্তা" স্ট্রিং রাখে। আরও কি, এই স্ট্রিংটি সারি থেকে না পাওয়া পর্যন্ত এটি বন্ধ হবে। আপনি এই বিষয় সম্পর্কে আরও জানতে "
SynchronousQueue vs Exchanger " পড়তে পারেন ৷
ফেসার
আমরা শেষের জন্য সেরাটি সংরক্ষণ করেছি —
Phaser
. আমরা ক্লাস আমদানি করতে হবে
java.util.concurrent.Phaser
. আসুন একটি সাধারণ উদাহরণ দেখি:
public static void main(String[] args) throws InterruptedException {
Phaser phaser = new Phaser();
// By calling the register method, we register the current (main) thread as a party
phaser.register();
System.out.println("Phasecount is " + phaser.getPhase());
testPhaser(phaser);
testPhaser(phaser);
testPhaser(phaser);
// After 3 seconds, we arrive at the barrier and deregister. Number of arrivals = number of registrations = start
Thread.sleep(3000);
phaser.arriveAndDeregister();
System.out.println("Phasecount is " + phaser.getPhase());
}
private static void testPhaser(final Phaser phaser) {
// We indicate that there will be a +1 party on the Phaser
phaser.register();
// Start a new thread
new Thread(() -> {
String name = Thread.currentThread().getName();
System.out.println(name + " arrived");
phaser.arriveAndAwaitAdvance(); // The threads register arrival at the phaser.
System.out.println(name + " after passing barrier");
}).start();
}
উদাহরণটি ব্যাখ্যা করে যে ব্যবহার করার সময়
Phaser
, বাধা ভেঙে যায় যখন রেজিস্ট্রেশনের সংখ্যা বাধায় আগমনের সংখ্যার সাথে মেলে।
আপনি এই GeeksforGeeks নিবন্ধটিPhaser
পড়ার মাধ্যমে আরও পরিচিত হতে পারেন ।
সারসংক্ষেপ
আপনি এই উদাহরণগুলি থেকে দেখতে পাচ্ছেন, থ্রেড সিঙ্ক্রোনাইজ করার বিভিন্ন উপায় রয়েছে। এর আগে, আমি মাল্টিথ্রেডিংয়ের দিকগুলি স্মরণ করার চেষ্টা করেছি। আমি এই সিরিজের আগের কিস্তি দরকারী ছিল আশা করি. কিছু লোক বলে যে মাল্টিথ্রেডিংয়ের পথটি "জাভা কনকারেন্সি ইন প্র্যাকটিস" বইটি দিয়ে শুরু হয়। যদিও এটি 2006 সালে প্রকাশিত হয়েছিল, লোকেরা বলে যে বইটি বেশ ভিত্তিগত এবং আজও প্রাসঙ্গিক। উদাহরণস্বরূপ, আপনি এখানে আলোচনা পড়তে পারেন:
"জাভা কনকারেন্সি ইন প্র্যাকটিস" কি এখনও বৈধ? . আলোচনার লিঙ্কগুলি পড়তেও এটি দরকারী।
উদাহরণস্বরূপ, দ্য ওয়েল-গ্রাউন্ডেড জাভা ডেভেলপার বইটির একটি লিঙ্ক রয়েছে এবং আমরা
অধ্যায় 4-এর বিশেষ উল্লেখ করব। আধুনিক সমাহার । এই বিষয় সম্পর্কে একটি সম্পূর্ণ পর্যালোচনা আছে:
জাভা 8 এর যুগে কি "জাভা কনকারেন্সি ইন প্র্যাকটিস" এখনও বৈধ? সেই নিবন্ধটি এই বিষয়টিকে সত্যিকার অর্থে বোঝার জন্য আর কী পড়তে হবে সে সম্পর্কেও পরামর্শ দেয়।
এর পরে, আপনি OCA/OCP Java SE 8 প্রোগ্রামার প্র্যাকটিস টেস্টের মতো একটি দুর্দান্ত বই দেখতে পারেন । আমরা দ্বিতীয় সংক্ষিপ্ত বিবরণে আগ্রহী: OCP (ওরাকল সার্টিফাইড প্রফেশনাল)। আপনি "অধ্যায় 20: জাভা কনকারেন্সি" এ পরীক্ষাগুলি পাবেন। এই বইটিতে ব্যাখ্যা সহ প্রশ্ন এবং উত্তর উভয়ই রয়েছে। উদাহরণস্বরূপ:
![একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট VI — আগুন দূরে! - 3]()
অনেকে বলতে শুরু করতে পারে যে এই প্রশ্নটি পদ্ধতিগুলির মুখস্থ করার আরেকটি উদাহরণ। একদিকে, হ্যাঁ। অন্যদিকে, আপনি মনে করে এই প্রশ্নের উত্তর দিতে পারেন এটি
ExecutorService
এক ধরনের "আপগ্রেড"
Executor
। এবং
Executor
থ্রেডগুলি যেভাবে তৈরি করা হয় তা কেবল লুকানোর উদ্দেশ্যে করা হয়েছে, তবে এটি চালানোর মূল উপায় নয়, অর্থাৎ,
Runnable
একটি নতুন থ্রেডে একটি বস্তু শুরু করা। এই কারণেই সেখানে নেই
execute(Callable)
— কারণ
ExecutorService
,
Executor
সহজভাবে
submit()
এমন পদ্ধতি যোগ করে যা একটি
Future
বস্তুকে ফিরিয়ে দিতে পারে। অবশ্যই, আমরা পদ্ধতির একটি তালিকা মুখস্থ করতে পারি, তবে ক্লাসের প্রকৃতি সম্পর্কে আমাদের জ্ঞানের উপর ভিত্তি করে আমাদের উত্তর তৈরি করা অনেক সহজ। এবং এখানে এই বিষয়ে কিছু অতিরিক্ত উপকরণ রয়েছে:
একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট I — এক্সিকিউশনের থ্রেডগুলি একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট II — সিঙ্ক্রোনাইজেশন আরও ভাল একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট III — মিথস্ক্রিয়া আরও ভাল একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট IV — কলযোগ্য, ভবিষ্যত এবং বন্ধুরা একসাথে আরও ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট V — এক্সিকিউটর, থ্রেডপুল, ফর্ক/যোগদান
GO TO FULL VERSION