CodeGym /Java Blog /এলোমেলো /একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট I — থ্রেডস অফ এক্...
John Squirrels
লেভেল 41
San Francisco

একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট I — থ্রেডস অফ এক্সিকিউশন

এলোমেলো দলে প্রকাশিত

ভূমিকা

মাল্টিথ্রেডিং প্রথম থেকেই জাভাতে তৈরি করা হয়েছিল। সুতরাং, আসুন সংক্ষেপে মাল্টিথ্রেডিং নামক এই জিনিসটি দেখুন। একসাথে ভাল: জাভা এবং থ্রেড ক্লাস।  পার্ট I — থ্রেডস অফ এক্সিকিউশন - 1আমরা ওরাকল থেকে একটি রেফারেন্স পয়েন্ট হিসাবে অফিসিয়াল পাঠ গ্রহণ করি: " পাঠ: "হ্যালো ওয়ার্ল্ড!" অ্যাপ্লিকেশন "। আমরা আমাদের হ্যালো ওয়ার্ল্ড প্রোগ্রামের কোডটি নিম্নরূপ পরিবর্তন করব:

class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsপ্রোগ্রামটি শুরু হলে পাস করা ইনপুট প্যারামিটারের একটি অ্যারে। এই কোডটি এমন একটি ফাইলে সংরক্ষণ করুন যা ক্লাসের নামের সাথে মেলে এবং এক্সটেনশন রয়েছে .javajavac ইউটিলিটি ব্যবহার করে এটি কম্পাইল করুন : javac HelloWorldApp.java. তারপর, আমরা কিছু প্যারামিটার দিয়ে আমাদের কোড চালাই, উদাহরণস্বরূপ, "রজার": java HelloWorldApp Roger একসাথে ভাল: জাভা এবং থ্রেড ক্লাস।  পার্ট I — মৃত্যুদণ্ডের থ্রেডস - 2আমাদের কোডে বর্তমানে একটি গুরুতর ত্রুটি রয়েছে। আপনি যদি কোনো আর্গুমেন্ট পাস না করেন (যেমন শুধু "java HelloWorldApp" চালান), তাহলে আমরা একটি ত্রুটি পাই:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
"প্রধান" নামের থ্রেডে একটি ব্যতিক্রম (অর্থাৎ একটি ত্রুটি) ঘটেছে। সুতরাং, জাভা থ্রেড আছে? এখান থেকেই আমাদের যাত্রা শুরু।

জাভা এবং থ্রেড

একটি থ্রেড কি তা বোঝার জন্য, আপনাকে বুঝতে হবে কিভাবে একটি জাভা প্রোগ্রাম শুরু হয়। আসুন আমাদের কোডটি নিম্নরূপ পরিবর্তন করি:

class HelloWorldApp {
    public static void main(String[] args) {
		while (true) { 
			// Do nothing
		}
	}
}
এখন এর সাথে আবার কম্পাইল করা যাক javac। সুবিধার জন্য, আমরা একটি পৃথক উইন্ডোতে আমাদের জাভা কোড চালাব। উইন্ডোজে, এটি এইভাবে করা যেতে পারে: start java HelloWorldApp. এখন আমরা jps ইউটিলিটি ব্যবহার করব জাভা আমাদের কী তথ্য জানাতে পারে তা দেখতে: একসাথে ভাল: জাভা এবং থ্রেড ক্লাস।  পার্ট I — মৃত্যুদণ্ডের থ্রেডস - 3প্রথম নম্বরটি হল পিআইডি বা প্রসেস আইডি। একটি প্রক্রিয়া কি?

A process is a combination of code and data sharing a common virtual address space.
প্রক্রিয়াগুলির সাথে, বিভিন্ন প্রোগ্রামগুলি চালানোর সাথে সাথে একে অপরের থেকে বিচ্ছিন্ন হয়ে যায়: প্রতিটি অ্যাপ্লিকেশন অন্যান্য প্রোগ্রামগুলিতে হস্তক্ষেপ না করেই মেমরিতে তার নিজস্ব এলাকা ব্যবহার করে। আরও জানতে, আমি এই টিউটোরিয়ালটি পড়ার পরামর্শ দিচ্ছি: প্রক্রিয়া এবং থ্রেড । একটি প্রক্রিয়া একটি থ্রেড ছাড়া বিদ্যমান থাকতে পারে না, তাই যদি একটি প্রক্রিয়া বিদ্যমান থাকে, তাহলে এটি অন্তত একটি থ্রেড আছে. কিন্তু কিভাবে এই জাভা সম্পর্কে আসা? যখন আমরা একটি জাভা প্রোগ্রাম শুরু করি, তখন মেথড দিয়ে এক্সিকিউশন শুরু হয় main। এটা যেন আমরা প্রোগ্রামে পা রাখছি, তাই এই বিশেষ mainপদ্ধতিটিকে এন্ট্রি পয়েন্ট বলা হয়। পদ্ধতিটি mainসর্বদা "পাবলিক স্ট্যাটিক ভ্যাইড" হতে হবে, যাতে জাভা ভার্চুয়াল মেশিন (JVM) আমাদের প্রোগ্রাম চালানো শুরু করতে পারে। আরও তথ্যের জন্য, জাভা প্রধান পদ্ধতি স্ট্যাটিক কেন?. দেখা যাচ্ছে যে জাভা লঞ্চার (java.exe বা javaw.exe) হল একটি সাধারণ সি অ্যাপ্লিকেশন: এটি বিভিন্ন DLL লোড করে যা প্রকৃতপক্ষে JVM-এর অন্তর্ভুক্ত। জাভা লঞ্চার জাভা নেটিভ ইন্টারফেস (জেএনআই) কলগুলির একটি নির্দিষ্ট সেট করে। JNI হল জাভা ভার্চুয়াল মেশিনের জগতকে C++ এর জগতের সাথে সংযুক্ত করার একটি প্রক্রিয়া। সুতরাং, লঞ্চারটি নিজেই JVM নয়, বরং এটি লোড করার একটি প্রক্রিয়া। এটি JVM শুরু করার জন্য কার্যকর করার জন্য সঠিক কমান্ডগুলি জানে। এটি প্রয়োজনীয় পরিবেশ সেট আপ করতে JNI কলগুলি কীভাবে ব্যবহার করতে হয় তা জানে৷ এই পরিবেশ সেট আপ করার মধ্যে প্রধান থ্রেড তৈরি করা অন্তর্ভুক্ত, যাকে অবশ্যই "প্রধান" বলা হয়। জাভা প্রক্রিয়ায় কোন থ্রেড বিদ্যমান তা আরও ভালভাবে ব্যাখ্যা করার জন্য, আমরা jvisualvm ব্যবহার করিটুল, যা JDK এর সাথে অন্তর্ভুক্ত। একটি প্রক্রিয়ার পিড জেনে, আমরা অবিলম্বে সেই প্রক্রিয়া সম্পর্কে তথ্য দেখতে পারি: jvisualvm --openpid <process id> একসাথে ভাল: জাভা এবং থ্রেড ক্লাস।  পার্ট I — মৃত্যুদণ্ডের থ্রেড - 4মজার বিষয় হল, প্রতিটি থ্রেডের মেমরিতে আলাদা আলাদা এলাকা রয়েছে যা প্রক্রিয়াটির জন্য বরাদ্দ করা হয়েছে। এই মেমরি গঠন একটি স্ট্যাক বলা হয়. একটি স্ট্যাক ফ্রেম নিয়ে গঠিত। একটি ফ্রেম একটি পদ্ধতির সক্রিয়করণের প্রতিনিধিত্ব করে (একটি অসমাপ্ত পদ্ধতি কল)। একটি ফ্রেমকে StackTraceElement হিসেবেও উপস্থাপন করা যেতে পারে ( StackTraceElement এর জন্য Java API দেখুন )। আপনি এখানে আলোচনায় প্রতিটি থ্রেডে বরাদ্দ করা মেমরি সম্পর্কে আরও তথ্য পেতে পারেন: " কিভাবে Java (JVM) প্রতিটি থ্রেডের জন্য স্ট্যাক বরাদ্দ করে "। আপনি যদি Java API দেখেন এবং "থ্রেড" শব্দটি অনুসন্ধান করেন, তাহলে আপনি java.lang.Thread খুঁজে পাবেনক্লাস এটি এমন একটি ক্লাস যা জাভাতে একটি থ্রেড উপস্থাপন করে এবং আমাদের এটির সাথে কাজ করতে হবে। একসাথে ভাল: জাভা এবং থ্রেড ক্লাস।  পার্ট I — থ্রেডস অফ এক্সিকিউশন - 5

java.lang.থ্রেড

জাভাতে, একটি থ্রেড ক্লাসের একটি উদাহরণ দ্বারা প্রতিনিধিত্ব করা হয় java.lang.Thread। আপনার অবিলম্বে বুঝতে হবে যে থ্রেড ক্লাসের উদাহরণগুলি নিজেরাই কার্যকর করার থ্রেড নয়। এটি JVM এবং অপারেটিং সিস্টেম দ্বারা পরিচালিত নিম্ন-স্তরের থ্রেডগুলির জন্য এক ধরনের API। যখন আমরা জাভা লঞ্চার ব্যবহার করে JVM শুরু করি, তখন এটি main"প্রধান" নামে একটি থ্রেড এবং কয়েকটি অন্যান্য গৃহস্থালি থ্রেড তৈরি করে। থ্রেড ক্লাসের জন্য JavaDoc এ যেমন বলা হয়েছে: When a Java Virtual Machine starts up, there is usually a single non-daemon thread. থ্রেড 2 ধরনের আছে: ডেমন এবং নন-ডেমন। ডেমন থ্রেড হল ব্যাকগ্রাউন্ড (হাউসকিপিং) থ্রেড যা ব্যাকগ্রাউন্ডে কিছু কাজ করে। "ডেমন" শব্দটি ম্যাক্সওয়েলের রাক্ষসকে বোঝায়। আপনি এই উইকিপিডিয়া নিবন্ধে আরও জানতে পারেন । ডকুমেন্টেশনে যেমন বলা হয়েছে, JVM প্রোগ্রামটি (প্রক্রিয়া) চালিয়ে যাচ্ছে যতক্ষণ না:
  • Runtime.exit () পদ্ধতি বলা হয়
  • সমস্ত নন-ডেমন থ্রেড তাদের কাজ শেষ করে (ত্রুটি ছাড়া বা নিক্ষেপ করা ব্যতিক্রম ছাড়া)
এটি থেকে একটি গুরুত্বপূর্ণ বিশদ অনুসরণ করা হয়েছে: ডেমন থ্রেডগুলি যে কোনও সময়ে বন্ধ করা যেতে পারে। ফলস্বরূপ, তাদের ডেটার অখণ্ডতা সম্পর্কে কোনও গ্যারান্টি নেই। তদনুসারে, ডেমন থ্রেড নির্দিষ্ট গৃহস্থালি কাজের জন্য উপযুক্ত। উদাহরণস্বরূপ, জাভাতে একটি থ্রেড রয়েছে যা প্রক্রিয়াকরণ finalize()পদ্ধতি কলের জন্য দায়ী, যেমন থ্রেডগুলি আবর্জনা সংগ্রাহক (gc) এর সাথে জড়িত। প্রতিটি থ্রেড একটি গ্রুপের অংশ ( ThreadGroup )। এবং গোষ্ঠীগুলি অন্যান্য গোষ্ঠীর অংশ হতে পারে, একটি নির্দিষ্ট শ্রেণিবিন্যাস বা কাঠামো গঠন করে।

public static void main(String[] args) {
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
গোষ্ঠীগুলি থ্রেড পরিচালনায় শৃঙ্খলা আনে। গ্রুপ ছাড়াও, থ্রেডের নিজস্ব ব্যতিক্রম হ্যান্ডলার আছে। একটি উদাহরণ দেখুন:

public static void main(String[] args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
শূন্য দ্বারা বিভাজন একটি ত্রুটি সৃষ্টি করবে যা হ্যান্ডলার দ্বারা ধরা হবে। আপনি যদি আপনার নিজের হ্যান্ডলার নির্দিষ্ট না করেন, তাহলে JVM ডিফল্ট হ্যান্ডলারকে আহ্বান করবে, যা StdError-এ ব্যতিক্রমের স্ট্যাক ট্রেস আউটপুট করবে। প্রতিটি থ্রেডেরও একটি অগ্রাধিকার রয়েছে। আপনি এই নিবন্ধে অগ্রাধিকার সম্পর্কে আরও পড়তে পারেন: মাল্টিথ্রেডিং-এ জাভা থ্রেড অগ্রাধিকার

একটি থ্রেড তৈরি করা হচ্ছে

ডকুমেন্টেশনে উল্লিখিত হিসাবে, আমাদের কাছে একটি থ্রেড তৈরি করার 2 টি উপায় রয়েছে। প্রথম উপায় হল আপনার নিজের সাবক্লাস তৈরি করা। উদাহরণ স্বরূপ:

public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");  
        }
    }
    
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}
আপনি দেখতে পাচ্ছেন, টাস্কের কাজটি পদ্ধতিতে ঘটে run(), তবে থ্রেডটি নিজেই পদ্ধতিতে শুরু হয় start()। এই পদ্ধতিগুলিকে বিভ্রান্ত করবেন না: যদি আমরা সরাসরি r un()পদ্ধতিকে কল করি, তাহলে কোন নতুন থ্রেড শুরু হবে না। এটি এমন start()পদ্ধতি যা JVM কে একটি নতুন থ্রেড তৈরি করতে বলে। এই অপশনটি যেখানে আমরা থ্রেড ইনহেরিট করি তা ইতিমধ্যেই খারাপ যে আমরা আমাদের ক্লাস হায়ারার্কিতে থ্রেড অন্তর্ভুক্ত করছি। দ্বিতীয় ত্রুটি হল যে আমরা "একক দায়িত্ব" নীতি লঙ্ঘন করতে শুরু করছি। অর্থাৎ, আমাদের ক্লাস একই সাথে থ্রেড নিয়ন্ত্রণ করার জন্য এবং এই থ্রেডে কিছু কাজ সম্পাদন করার জন্য দায়ী। সঠিক উপায় কি? উত্তরটি একই পদ্ধতিতে পাওয়া যায় run(), যা আমরা ওভাররাইড করি:

public void run() {
	if (target != null) {
		target.run();
	}
}
এখানে, targetকিছু আছে java.lang.Runnable, যা আমরা থ্রেড ক্লাসের একটি উদাহরণ তৈরি করার সময় পাস করতে পারি। এর মানে আমরা এটি করতে পারি:

public class HelloWorld{
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            } 
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Runnableজাভা 1.8 থেকে একটি কার্যকরী ইন্টারফেস হয়েছে। এটি একটি থ্রেডের টাস্কের জন্য আরও সুন্দর কোড লেখা সম্ভব করে তোলে:

public static void main(String[] args) {
	Runnable task = () -> { 
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

উপসংহার

আমি আশা করি এই আলোচনাটি একটি থ্রেড কী, কীভাবে থ্রেডগুলি অস্তিত্বে আসে এবং থ্রেডগুলির সাথে কী মৌলিক ক্রিয়াকলাপগুলি করা যেতে পারে তা স্পষ্ট করে। পরের অংশে , আমরা বোঝার চেষ্টা করব কীভাবে থ্রেডগুলি একে অপরের সাথে যোগাযোগ করে এবং থ্রেডের জীবনচক্রটি অন্বেষণ করে। একসাথে ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট II — সিঙ্ক্রোনাইজেশন আরও ভাল একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট III — মিথস্ক্রিয়া আরও ভাল একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট IV — কলযোগ্য, ভবিষ্যত এবং বন্ধুরা একসাথে আরও ভাল: জাভা এবং থ্রেড ক্লাস। পার্ট V — এক্সিকিউটর, থ্রেডপুল, ফর্ক/জইন বেটার একসাথে: জাভা এবং থ্রেড ক্লাস। পার্ট VI — আগুন দূরে!
মন্তব্য
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION