CodeGym /Java Blog /এলোমেলো /জাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্ত...
John Squirrels
লেভেল 41
San Francisco

জাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্তর। অংশ ২

এলোমেলো দলে প্রকাশিত
জাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্তর। অংশ 1জাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্তর।  পর্ব 2 - 1

মাল্টিথ্রেডিং

24. আমি কিভাবে জাভাতে একটি নতুন থ্রেড তৈরি করব?

এক বা অন্য উপায়, থ্রেড ক্লাস ব্যবহার করে একটি থ্রেড তৈরি করা হয়। তবে এটি করার বিভিন্ন উপায় রয়েছে…
  1. java.lang.Thread ইনহেরিট করুন ।
  2. java.lang.Runnable ইন্টারফেস প্রয়োগ করুন — থ্রেড ক্লাসের কনস্ট্রাক্টর একটি Runnable অবজেক্ট নেয়।
আসুন তাদের প্রতিটি সম্পর্কে কথা বলি।

থ্রেড ক্লাস ইনহেরিট করুন

এই ক্ষেত্রে, আমরা আমাদের ক্লাসকে java.lang.Thread ইনহেরিট করি । এটির একটি রান() পদ্ধতি রয়েছে এবং এটিই আমাদের প্রয়োজন। নতুন থ্রেডের সমস্ত জীবন এবং যুক্তি এই পদ্ধতিতে থাকবে। এটি নতুন থ্রেডের জন্য একটি প্রধান পদ্ধতির মতো । এর পরে, যা অবশিষ্ট থাকে তা হল আমাদের ক্লাসের একটি অবজেক্ট তৈরি করা এবং start() পদ্ধতিতে কল করা। এটি একটি নতুন থ্রেড তৈরি করবে এবং এর যুক্তি কার্যকর করা শুরু করবে। একবার দেখা যাক:

/**
* An example of how to create threads by inheriting the {@link Thread} class.
*/
class ThreadInheritance extends Thread {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance threadInheritance1 = new ThreadInheritance();
       ThreadInheritance threadInheritance2 = new ThreadInheritance();
       ThreadInheritance threadInheritance3 = new ThreadInheritance();
       threadInheritance1.start();
       threadInheritance2.start();
       threadInheritance3.start();
   }
}
কনসোল আউটপুট এই মত কিছু হবে:
থ্রেড-1 থ্রেড-0 থ্রেড-2
অর্থাৎ, এখানেও আমরা দেখতে পাই যে থ্রেডগুলি ক্রমানুসারে চালানো হয় না, বরং JVM তাদের চালানোর জন্য উপযুক্ত বলে মনে করে :)

রানেবল ইন্টারফেস প্রয়োগ করুন

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

/**
* An example of how to create threads from the {@link Runnable} interface.
* It's easier than easy — we implement this interface and then pass an instance of our object
* to the constructor.
*/
class ThreadInheritance implements Runnable {

   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }

   public static void main(String[] args) {
       ThreadInheritance runnable1 = new ThreadInheritance();
       ThreadInheritance runnable2 = new ThreadInheritance();
       ThreadInheritance runnable3 = new ThreadInheritance();

       Thread threadRunnable1 = new Thread(runnable1);
       Thread threadRunnable2 = new Thread(runnable2);
       Thread threadRunnable3 = new Thread(runnable3);

       threadRunnable1.start();
       threadRunnable2.start();
       threadRunnable3.start();
   }
}
এবং এখানে ফলাফল:
থ্রেড-0 থ্রেড-1 থ্রেড-2

25. একটি প্রক্রিয়া এবং একটি থ্রেড মধ্যে পার্থক্য কি?

জাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্তর।  পর্ব 2 - 2একটি প্রক্রিয়া এবং একটি থ্রেড নিম্নলিখিত উপায়ে ভিন্ন:
  1. একটি চলমান প্রোগ্রামকে একটি প্রক্রিয়া বলা হয়, তবে একটি থ্রেড একটি প্রক্রিয়ার একটি অংশ।
  2. প্রক্রিয়াগুলি স্বাধীন, তবে থ্রেডগুলি একটি প্রক্রিয়ার অংশ।
  3. প্রসেসগুলির মেমরিতে বিভিন্ন ঠিকানার স্থান থাকে, তবে থ্রেডগুলি একটি সাধারণ ঠিকানার স্থান ভাগ করে।
  4. থ্রেডগুলির মধ্যে প্রসঙ্গ পরিবর্তন প্রক্রিয়াগুলির মধ্যে স্যুইচ করার চেয়ে দ্রুত।
  5. আন্তঃ-প্রক্রিয়া যোগাযোগ আন্তঃ-থ্রেড যোগাযোগের চেয়ে ধীর এবং ব্যয়বহুল।
  6. একটি অভিভাবক প্রক্রিয়ার কোনো পরিবর্তন একটি শিশু প্রক্রিয়া প্রভাবিত করে না, কিন্তু একটি অভিভাবক থ্রেড পরিবর্তন একটি শিশু থ্রেড প্রভাবিত করতে পারে.

26. মাল্টিথ্রেডিং এর সুবিধা কি কি?

  1. মাল্টিথ্রেডিং একটি অ্যাপ্লিকেশন/প্রোগ্রামকে সর্বদা ইনপুটের প্রতি প্রতিক্রিয়াশীল হতে দেয়, এমনকি যদি এটি ইতিমধ্যে কিছু ব্যাকগ্রাউন্ড কাজ চালায়;
  2. মাল্টিথ্রেডিং কাজগুলি দ্রুত সম্পন্ন করা সম্ভব করে, কারণ থ্রেডগুলি স্বাধীনভাবে চলে;
  3. মাল্টিথ্রেডিং ক্যাশে মেমরির আরও ভালো ব্যবহার প্রদান করে, কারণ থ্রেড শেয়ার করা মেমরি রিসোর্স অ্যাক্সেস করতে পারে;
  4. মাল্টিথ্রেডিং প্রয়োজনীয় সার্ভারের সংখ্যা হ্রাস করে, কারণ একটি সার্ভার একসাথে একাধিক থ্রেড চালাতে পারে।

27. একটি থ্রেডের জীবনচক্রের রাজ্যগুলি কী কী?

জাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্তর।  পর্ব 2 - 3
  1. নতুন: এই অবস্থায়, নতুন অপারেটর ব্যবহার করে থ্রেড অবজেক্ট তৈরি করা হয়েছে, কিন্তু একটি নতুন থ্রেড এখনও বিদ্যমান নেই। আমরা start() মেথড কল না করা পর্যন্ত থ্রেড শুরু হয় না ।
  2. চালনাযোগ্য: এই অবস্থায়, থ্রেডটি start() এর পরে চালানোর জন্য প্রস্তুত। পদ্ধতি বলা হয়। যাইহোক, এটি এখনও থ্রেড শিডিউলারের দ্বারা নির্বাচিত হয়নি।
  3. চলমান: এই অবস্থায়, থ্রেড শিডিউলকারী একটি প্রস্তুত অবস্থা থেকে একটি থ্রেড বাছাই করে এবং এটি চলে।
  4. অপেক্ষা/অবরুদ্ধ: এই অবস্থায়, একটি থ্রেড চলছে না, কিন্তু এটি এখনও জীবিত বা অন্য থ্রেড সম্পূর্ণ হওয়ার জন্য অপেক্ষা করছে।
  5. মৃত/সমাপ্ত: যখন একটি থ্রেড রান() পদ্ধতি থেকে প্রস্থান করে, তখন এটি একটি মৃত বা সমাপ্ত অবস্থায় থাকে।

28. একটি থ্রেড দুইবার চালানো সম্ভব?

না, আমরা একটি থ্রেড পুনরায় চালু করতে পারি না, কারণ একটি থ্রেড শুরু হওয়ার পরে এবং চালানোর পরে, এটি মৃত অবস্থায় চলে যায়। যদি আমরা একটি থ্রেড দুইবার শুরু করার চেষ্টা করি, একটি java.lang.IllegalThreadStateException নিক্ষেপ করা হবে। একবার দেখা যাক:

class DoubleStartThreadExample extends Thread {

   /**
    * Simulate the work of a thread
    */
   public void run() {
	// Something happens. At this state, this is not essential.
   }

   /**
    * Start the thread twice
    */
   public static void main(String[] args) {
       DoubleStartThreadExample doubleStartThreadExample = new DoubleStartThreadExample();
       doubleStartThreadExample.start();
       doubleStartThreadExample.start();
   }
}
এক্সিকিউশন একই থ্রেডের দ্বিতীয় শুরুতে আসার সাথে সাথেই একটি ব্যতিক্রম হবে। এটি নিজে চেষ্টা করুন ;) এটি সম্পর্কে একশোবার শোনার চেয়ে এটি একবার দেখা ভাল।

29. আপনি যদি start() কল না করে সরাসরি run() কল করেন?

হ্যাঁ, আপনি অবশ্যই রান() পদ্ধতিতে কল করতে পারেন, তবে একটি নতুন থ্রেড তৈরি করা হবে না এবং পদ্ধতিটি একটি পৃথক থ্রেডে চলবে না। এই ক্ষেত্রে, আমরা একটি সাধারণ পদ্ধতি কল একটি সাধারণ বস্তু আছে. আমরা যদি start() পদ্ধতির কথা বলি, তাহলে সেটা অন্য ব্যাপার। যখন এই পদ্ধতিটি বলা হয়, JVM একটি নতুন থ্রেড শুরু করে। এই থ্রেড, ঘুরে, আমাদের পদ্ধতি কল ;) এটা বিশ্বাস করবেন না? এখানে, এটি চেষ্টা করুন:

class ThreadCallRunExample extends Thread {

   public void run() {
       for (int i = 0; i < 5; i++) {
           System.out.print(i);
       }
   }

   public static void main(String args[]) {
       ThreadCallRunExample runExample1 = new ThreadCallRunExample();
       ThreadCallRunExample runExample2 = new ThreadCallRunExample();

       // Two ordinary methods will be called in the main thread, one after the other.
       runExample1.run();
       runExample2.run();
   }
}
এবং কনসোল আউটপুট এই মত দেখাবে:
0123401234
আপনি দেখতে পাচ্ছেন, কোন থ্রেড তৈরি করা হয়নি। একটি সাধারণ ক্লাসের মতোই সবকিছু কাজ করেছিল। প্রথমত, প্রথম বস্তুর পদ্ধতিটি কার্যকর করা হয়েছিল এবং তারপরে দ্বিতীয়টি।

30. ডেমন থ্রেড কি?

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

কেন জাভা একটি ডেমন থ্রেড বন্ধ করে?

ডেমন থ্রেডের একমাত্র উদ্দেশ্য হল ব্যবহারকারীর থ্রেডে পটভূমি সমর্থন প্রদান করা। তদনুসারে, যদি মূল থ্রেডটি বন্ধ করা হয়, তাহলে JVM স্বয়ংক্রিয়ভাবে তার সমস্ত ডেমন থ্রেড বন্ধ করে দেয়।

থ্রেড ক্লাসের পদ্ধতি

java.lang.Thread ক্লাস একটি ডেমন থ্রেডের সাথে কাজ করার জন্য দুটি পদ্ধতি প্রদান করে :
  1. public void setDaemon(বুলিয়ান স্থিতি) — এই পদ্ধতিটি নির্দেশ করে যে এটি একটি ডেমন থ্রেড হবে কিনা। ডিফল্ট মিথ্যা . এর মানে হল যে কোন ডেমন থ্রেড তৈরি করা হবে না যদি না আপনি বিশেষভাবে এটি বলেন।
  2. পাবলিক বুলিয়ান isDaemon() — এই পদ্ধতিটি মূলত ডেমন ভেরিয়েবলের জন্য একটি গেটার, যা আমরা পূর্ববর্তী পদ্ধতি ব্যবহার করে সেট করেছি।
উদাহরণ:

class DaemonThreadExample extends Thread {

   public void run() {
       // Checks whether this thread is a daemon
       if (Thread.currentThread().isDaemon()) {
           System.out.println("daemon thread");
       } else {
           System.out.println("user thread");
       }
   }

   public static void main(String[] args) {
       DaemonThreadExample thread1 = new DaemonThreadExample();
       DaemonThreadExample thread2 = new DaemonThreadExample();
       DaemonThreadExample thread3 = new DaemonThreadExample();

       // Make thread1 a daemon thread.
       thread1.setDaemon(true);

       System.out.println("daemon? " + thread1.isDaemon());
       System.out.println("daemon? " + thread2.isDaemon());
       System.out.println("daemon? " + thread3.isDaemon());

       thread1.start();
       thread2.start();
       thread3.start();
   }
}
কনসোল আউটপুট:
ডেমন? সত্যিকারের ডেমন? মিথ্যা ডেমন? মিথ্যা ডেমন থ্রেড ব্যবহারকারী থ্রেড ব্যবহারকারী থ্রেড
আউটপুট থেকে, আমরা দেখতে পাচ্ছি যে থ্রেডের ভিতরেই, আমরা স্ট্যাটিক currentThread() পদ্ধতিটি ব্যবহার করে খুঁজে বের করতে পারি এটি কোন থ্রেড। বিকল্পভাবে, যদি আমাদের কাছে থ্রেড অবজেক্টের একটি রেফারেন্স থাকে তবে আমরা সরাসরি এটি থেকেও জানতে পারি। এটি কনফিগারযোগ্যতার প্রয়োজনীয় স্তর সরবরাহ করে।

31. একটি থ্রেড তৈরি করার পরে এটি একটি ডেমন করা সম্ভব?

না। আপনি যদি এটি করার চেষ্টা করেন, তাহলে আপনি একটি IllegalThreadStateException পাবেন । এর মানে আমরা এটি শুরু করার আগে শুধুমাত্র একটি ডেমন থ্রেড তৈরি করতে পারি। উদাহরণ:

class SetDaemonAfterStartExample extends Thread {

   public void run() {
       System.out.println("Working...");
   }

   public static void main(String[] args) {
       SetDaemonAfterStartExample afterStartExample = new SetDaemonAfterStartExample();
       afterStartExample.start();
      
       // An exception will be thrown here
       afterStartExample.setDaemon(true);
   }
}
কনসোল আউটপুট:
কাজ করছে... থ্রেড "প্রধান" java.lang.IllegalThreadStateException এ java.lang.Thread.setDaemon(Thread.java:1359) SetDaemonAfterStartExample.main(SetDaemonAfterStartExample.java:14) এ ব্যতিক্রম

32. শাটডাউন হুক কি?

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

Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
উদাহরণে দেখানো হয়েছে:

/**
* A program that shows how to start a shutdown hook thread,
* which will be executed right before the JVM shuts down
*/
class ShutdownHookThreadExample extends Thread {

   public void run() {
       System.out.println("shutdown hook executed");
   }

   public static void main(String[] args) {

       Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());

       System.out.println("Now the program is going to fall asleep. Press Ctrl+C to terminate it.");
       try {
           Thread.sleep(60000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }
}
কনসোল আউটপুট:
এখন ঘুমিয়ে পড়ার কর্মসূচি চলছে। এটি বন্ধ করতে Ctrl+C টিপুন। শাটডাউন হুক মৃত্যুদন্ড কার্যকর করা হয়েছে

33. সিঙ্ক্রোনাইজেশন কি?

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

একটি পদ্ধতি সিঙ্ক্রোনাইজ করা

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

/**
* An example where we synchronize a method. That is, we add the synchronized keyword to it.
* There are two authors who want to use one printer. Each of them has composed their own poems
* And of course they don’t want their poems mixed up. Instead, they want work to be performed in * * * order for each of them
*/
class Printer {

   synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer  = new Printer();

       // Create two threads
       Writer1 writer1 = new Writer1(printer);
       Writer2 writer2 = new Writer2(printer);

       // Start them
       writer1.start();
       writer2.start();
   }
}

/**
* Author No. 1, who writes an original poem.
*/
class Writer1 extends Thread {
   Printer printer;

   Writer1(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<string> poem = Arrays.asList("I ", this.getName(), " Write", " A Letter");
       printer.print(poem);
   }

}

/**
* Author No. 2, who writes an original poem.
*/
class Writer2 extends Thread {
   Printer printer;

   Writer2(Printer printer) {
       this.printer = printer;
   }

   public void run() {
       List<String> poem = Arrays.asList("I Do Not ", this.getName(), " Not Write", " No Letter");
       printer.print(poem);
   }
}
এবং কনসোল আউটপুট হল:
I Thread-0 Write A Letter I Do not Thread-1 Not Write No Letter

সিঙ্ক্রোনাইজেশন ব্লক

একটি সিঙ্ক্রোনাইজড ব্লক একটি পদ্ধতিতে কোনো নির্দিষ্ট সম্পদে সিঙ্ক্রোনাইজেশন সঞ্চালন করতে ব্যবহার করা যেতে পারে। ধরা যাক যে একটি বড় পদ্ধতিতে (হ্যাঁ, আপনার সেগুলি লেখা উচিত নয়, তবে কখনও কখনও সেগুলি ঘটে) আপনাকে কিছু কারণে শুধুমাত্র একটি ছোট অংশ সিঙ্ক্রোনাইজ করতে হবে। আপনি যদি একটি সিঙ্ক্রোনাইজড ব্লকে পদ্ধতির সমস্ত কোড রাখেন তবে এটি একটি সিঙ্ক্রোনাইজড পদ্ধতির মতোই কাজ করবে। সিনট্যাক্স এই মত দেখায়:

synchronized ("object to be locked") {
   // The code that must be protected
}
আগের উদাহরণের পুনরাবৃত্তি এড়াতে, আমরা বেনামী ক্লাস ব্যবহার করে থ্রেড তৈরি করব, অর্থাৎ আমরা অবিলম্বে রানেবল ইন্টারফেস বাস্তবায়ন করব।

/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   void print(List<String> wordsToPrint) {
       synchronized (this) {
           wordsToPrint.forEach(System.out::print);
       }
       System.out.println();
   }

   public static void main(String args[]) {
       // One object for two threads
       Printer printer = new Printer();

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}

}
এবং কনসোল আউটপুট হল:
আমি লেখক1 একটি চিঠি লিখি আমি লিখি না2 কোন চিঠি লিখি না

স্ট্যাটিক সিঙ্ক্রোনাইজেশন

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

/**
* This is how a synchronization block is added.
* Inside the block, you need to specify which object's mutex will be acquired.
*/
class Printer {

   static synchronized void print(List<String> wordsToPrint) {
       wordsToPrint.forEach(System.out::print);
       System.out.println();
   }

   public static void main(String args[]) {

       // Create two threads
       Thread writer1 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I ", "Writer1", " Write", " A Letter");
               Printer.print(poem);
           }
       });
       Thread writer2 = new Thread(new Runnable() {
           @Override
           public void run() {
               List<String> poem = Arrays.asList("I Do Not ", "Writer2", " Not Write", " No Letter");
               Printer.print(poem);
           }
       });

       // Start them
       writer1.start();
       writer2.start();
   }
}
এবং কনসোল আউটপুট হল:
আমি লিখি না2 চিঠি লিখি না আমি লেখক1 একটি চিঠি লিখি

34. একটি উদ্বায়ী চলক কি?

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

private volatile AtomicInteger count;
আমরা শুধু ভেরিয়েবলে উদ্বায়ী যোগ করি। কিন্তু মনে রাখবেন যে এর অর্থ সম্পূর্ণ থ্রেড নিরাপত্তা নয়... সর্বোপরি, ভেরিয়েবলের অপারেশন পারমাণবিক নাও হতে পারে। এটি বলেছে, আপনি পারমাণবিক ক্লাসগুলি ব্যবহার করতে পারেন যা পারমাণবিকভাবে কাজ করে, যেমন একটি সিপিইউ নির্দেশে। java.util.concurrent.atomic প্যাকেজে এরকম অনেক ক্লাস আছে ।

35. অচলাবস্থা কি?

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

class DeadLock {

   public static void main(String[] args) {
       final Integer r1 = 10;
       final Integer r2 = 15;

       DeadlockThread threadR1R2 = new DeadlockThread(r1, r2);
       DeadlockThread threadR2R1 = new DeadlockThread(r2, r1);

       new Thread(threadR1R2).start();
       new Thread(threadR2R1).start();
   }
}

/**
* A class that accepts two resources.
*/
class DeadlockThread implements Runnable {

   private final Integer r1;
   private final Integer r2;

   public DeadlockThread(Integer r1, Integer r2) {
       this.r1 = r1;
       this.r2 = r2;
   }

   @Override
   public void run() {
       synchronized (r1) {
           System.out.println(Thread.currentThread().getName() + " acquired resource: " + r1);

           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           synchronized (r2) {
               System.out.println(Thread.currentThread().getName() + " acquired resource: " + r2);
           }
       }
   }
}
কনসোল আউটপুট:
প্রথম থ্রেড প্রথম সম্পদ অর্জন করেছে দ্বিতীয় থ্রেড দ্বিতীয় সম্পদ অর্জন করেছে

36. আপনি কিভাবে অচলাবস্থা এড়াবেন?

যেহেতু আমরা জানি কিভাবে অচলাবস্থা ঘটে, আমরা কিছু সিদ্ধান্তে আঁকতে পারি...
  • উপরের উদাহরণে, অচলাবস্থা ঘটে এই কারণে যে আমরা নেস্টেড লকিং করেছি। অর্থাৎ, আমাদের একটি সিঙ্ক্রোনাইজড ব্লকের ভিতরে একটি সিঙ্ক্রোনাইজড ব্লক আছে। এটি এড়াতে, নেস্টিংয়ের পরিবর্তে, আপনাকে একটি নতুন উচ্চতর বিমূর্ততা স্তর তৈরি করতে হবে, সিঙ্ক্রোনাইজেশনটিকে উচ্চ স্তরে নিয়ে যেতে হবে এবং নেস্টেড লকিংটি দূর করতে হবে।
  • আপনি যত বেশি লকিং করবেন, অচলাবস্থার সম্ভাবনা তত বেশি। অতএব, প্রতিবার আপনি একটি সিঙ্ক্রোনাইজড ব্লক যোগ করার সময়, আপনার সত্যিই এটির প্রয়োজন কিনা এবং আপনি একটি নতুন যুক্ত করা এড়াতে পারেন কিনা সে সম্পর্কে আপনাকে ভাবতে হবে।
  • Thread.join() ব্যবহার করে । একটি থ্রেড অন্য থ্রেডের জন্য অপেক্ষা করার সময় আপনি অচলাবস্থার মধ্যেও চালাতে পারেন। এই সমস্যা এড়াতে, আপনি join() পদ্ধতির জন্য একটি টাইমআউট সেট করার কথা বিবেচনা করতে পারেন।
  • যদি আমাদের একটি থ্রেড থাকে, তাহলে কোন অচলাবস্থা থাকবে না;)

37. একটি জাতি শর্ত কি?

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

int z = 0;

// Check
if (z < 5) {
// Act
   z = z + 5;
}
দুটি থ্রেড একই সাথে এই কোড ব্লকে প্রবেশ করতে পারে যখন z এখনও শূন্য থাকে এবং তারপর উভয় থ্রেড এর মান পরিবর্তন করতে পারে। ফলস্বরূপ, আমরা 5 এর প্রত্যাশিত মান পাব না। পরিবর্তে, আমরা 10 পাব। আপনি কীভাবে এটি এড়াবেন? আপনাকে চেক করার এবং অভিনয় করার আগে একটি লক অর্জন করতে হবে এবং তারপরে লকটি ছেড়ে দিতে হবে। অর্থাৎ, আপনাকে প্রথম থ্রেডটি if ব্লকে প্রবেশ করতে হবে, সমস্ত ক্রিয়া সম্পাদন করতে হবে, z পরিবর্তন করতে হবে এবং শুধুমাত্র তখনই পরবর্তী থ্রেডটিকে একই কাজ করার সুযোগ দিতে হবে। কিন্তু পরবর্তী থ্রেড if ব্লকে প্রবেশ করবে না, যেহেতু z এখন 5 হবে:

// Acquire the lock for z
if (z < 5) {
   z = z + 5;
}
// Release z's lock
===================================================

উপসংহারের পরিবর্তে

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

এবং সর্বদা হিসাবে, এখানে কিছু দরকারী লিঙ্ক আছে:

পড়ার জন্য আপনি সমস্ত ধন্যবাদ। শীঘ্রই দেখা হবে :) আমার GitHub প্রোফাইলজাভা কোরের জন্য শীর্ষ 50টি চাকরির ইন্টারভিউ প্রশ্ন ও উত্তর।  পর্ব 2 - 5
মন্তব্য
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION