CodeGym /Java Blogu /Rastgele /Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı. B...
John Squirrels
Seviye
San Francisco

Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı. Bölüm 2

grupta yayınlandı
Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı. Bölüm 1Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı.  Bölüm 2 - 1

çoklu iş parçacığı

24. Java'da nasıl yeni bir iş parçacığı oluşturabilirim?

Öyle ya da böyle, Thread sınıfı kullanılarak bir iş parçacığı oluşturulur. Ama bunu yapmanın çeşitli yolları var…
  1. java.lang.Thread öğesini devralın .
  2. Java.lang.Runnable arabirimini uygulayın — Thread sınıfının yapıcısı bir Runnable nesnesi alır.
Her biri hakkında konuşalım.

Thread sınıfını devral

Bu durumda, sınıfımızın java.lang.Thread miras almasını sağlıyoruz . Bir run() yöntemi var ve ihtiyacımız olan da bu. Yeni ipliğin tüm ömrü ve mantığı bu yöntemde olacaktır. Yeni iş parçacığı için bir tür ana yöntem gibidir . Bundan sonra geriye sadece sınıfımızın bir nesnesini yaratmak ve start() metodunu çağırmak kalıyor. Bu, yeni bir iş parçacığı oluşturacak ve mantığını yürütmeye başlayacaktır. Hadi bir bakalım:

/**
* 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();
   }
}
Konsol çıktısı şöyle bir şey olacaktır:
Konu-1 Konu-0 Konu-2
Yani, burada bile iş parçacıklarının sırayla değil, JVM'nin onları çalıştırmayı uygun gördüğü şekilde yürütüldüğünü görüyoruz :)

Runnable arabirimini uygulama

Kalıtıma karşıysanız ve/veya zaten başka bir sınıfı miras alıyorsanız, java.lang.Runnable arayüzünü kullanabilirsiniz. Burada yukarıdaki örnekte olduğu gibi run() metodunu implemente ederek sınıfımızın bu arayüzü implemente etmesini sağlıyoruz . Geriye kalan tek şey Thread nesneleri oluşturmaktır . Görünüşe göre daha fazla kod satırı daha kötü. Ancak mirasın ne kadar zararlı olduğunu ve bundan kesinlikle kaçınmanın daha iyi olduğunu biliyoruz;) Bir göz atın:

/**
* 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();
   }
}
Ve işte sonuç:
Konu-0 Konu-1 Konu-2

25. İşlem ile iş parçacığı arasındaki fark nedir?

Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı.  Bölüm 2 - 2Bir işlem ve bir iş parçacığı aşağıdaki şekillerde farklıdır:
  1. Çalışan bir programa süreç denir, ancak bir iş parçacığı bir sürecin parçasıdır.
  2. İşlemler bağımsızdır, ancak iş parçacıkları bir sürecin parçalarıdır.
  3. İşlemlerin bellekte farklı adres alanları vardır, ancak iş parçacıkları ortak bir adres alanını paylaşır.
  4. İş parçacıkları arasında bağlam geçişi, işlemler arasında geçiş yapmaktan daha hızlıdır.
  5. İşlemler arası iletişim, iş parçacıkları arası iletişimden daha yavaş ve daha pahalıdır.
  6. Bir üst süreçteki herhangi bir değişiklik, bir alt süreci etkilemez, ancak bir üst iş parçacığındaki değişiklikler bir alt iş parçacığını etkileyebilir.

26. Çoklu iş parçacığının faydaları nelerdir?

  1. Çoklu iş parçacığı, bir uygulamanın/programın, halihazırda bazı arka plan görevlerini çalıştırıyor olsa bile, her zaman girdiye yanıt vermesini sağlar;
  2. Çoklu iş parçacığı, iş parçacıkları bağımsız olarak çalıştığı için görevleri daha hızlı tamamlamayı mümkün kılar;
  3. Çoklu iş parçacığı, önbellek belleğinin daha iyi kullanılmasını sağlar, çünkü iş parçacıkları paylaşılan bellek kaynaklarına erişebilir;
  4. Çoklu kullanım, gereken sunucu sayısını azaltır, çünkü bir sunucu aynı anda birden çok iş parçacığını çalıştırabilir.

27. Bir iş parçacığının yaşam döngüsündeki durumlar nelerdir?

Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı.  Bölüm 2 - 3
  1. Yeni: Bu durumda, new operatörü kullanılarak Thread nesnesi oluşturulur, ancak henüz yeni bir thread yoktur. Start() yöntemini çağırana kadar iş parçacığı başlamaz .
  2. Çalıştırılabilir: Bu durumda, iş parçacığı start() işlevinden sonra çalışmaya hazırdır. yöntem denir. Ancak, iş parçacığı planlayıcı tarafından henüz seçilmemiştir.
  3. Çalışıyor: Bu durumda, iş parçacığı zamanlayıcısı hazır durumdaki bir iş parçacığını seçer ve çalışır.
  4. Bekliyor/Engellendi: bu durumda, bir iş parçacığı çalışmıyor ama hala yaşıyor veya başka bir iş parçacığının tamamlanmasını bekliyor.
  5. Ölü/Sonlandırılmış: Bir iş parçacığı run() yönteminden çıktığında , ölü veya sonlandırılmış durumdadır.

28. Bir iş parçacığını iki kez çalıştırmak mümkün mü?

Hayır, bir iş parçacığını yeniden başlatamayız çünkü bir iş parçacığı başlayıp çalıştıktan sonra Ölü duruma geçer. Bir ileti dizisini iki kez başlatmaya çalışırsak, bir java.lang.IllegalThreadStateException atılır. Hadi bir bakalım:

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();
   }
}
Yürütme aynı iş parçacığının ikinci başlangıcına gelir gelmez bir istisna olacaktır. Kendiniz deneyin ;) Bunu yüzlerce kez duymaktansa bir kez görmek daha iyidir.

29. Start()'ı çağırmadan doğrudan run()'u çağırırsanız ne olur?

Evet, run() yöntemini kesinlikle çağırabilirsiniz , ancak yeni bir iş parçacığı oluşturulmayacak ve yöntem ayrı bir iş parçacığı üzerinde çalışmayacaktır. Bu durumda, sıradan bir yöntemi çağıran sıradan bir nesnemiz var. start() yönteminden bahsediyorsak , o zaman bu başka bir konu. Bu metot çağrıldığında JVM yeni bir thread başlatır. Bu konu sırayla bizim yöntemimizi çağırır ;) Buna inanmıyor musunuz? İşte, bir deneyin:

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();
   }
}
Ve konsol çıktısı şöyle görünecek:
0123401234
Gördüğünüz gibi, hiçbir iş parçacığı oluşturulmadı. Her şey sıradan bir sınıfta olduğu gibi çalıştı. İlk olarak, ilk nesnenin yöntemi yürütüldü ve ardından ikincisi.

30. Arka plan programı dizisi nedir?

Arka plan programı iş parçacığı, görevleri başka bir iş parçacığından daha düşük önceliğe sahip bir iş parçacığıdır. Diğer bir deyişle görevi, yalnızca başka bir (ana) iş parçacığı ile birlikte yapılması gereken yardımcı görevleri gerçekleştirmektir. Çöp toplama, sonlandırıcı vb. gibi otomatik olarak çalışan birçok daemon iş parçacığı vardır.

Java neden bir daemon iş parçacığını sonlandırıyor?

Daemon iş parçacığının tek amacı, bir kullanıcının iş parçacığına arka plan desteği sağlamaktır. Buna göre, ana iş parçacığı sonlandırılırsa, JVM otomatik olarak tüm daemon iş parçacıklarını sonlandırır.

Thread sınıfının yöntemleri

Java.lang.Thread sınıfı, bir arka plan programı iş parçacığıyla çalışmak için iki yöntem sağlar:
  1. public void setDaemon(boolean status) — Bu yöntem, bunun bir arka plan programı dizisi olup olmayacağını gösterir. Varsayılan false . Bu, siz özellikle söylemediğiniz sürece hiçbir arka plan programı dizisinin oluşturulmayacağı anlamına gelir.
  2. public boolean isDaemon() — Bu yöntem, temelde önceki yöntemi kullanarak ayarladığımız daemon değişkeni için bir alıcıdır .
Örnek:

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();
   }
}
Konsol çıktısı:
arka plan programı gerçek daemon? sahte daemon? yanlış daemon iş parçacığı kullanıcı iş parçacığı kullanıcı iş parçacığı
Çıktıdan, iş parçacığının içinde, hangi iş parçacığı olduğunu bulmak için statik currentThread() yöntemini kullanabileceğimizi görüyoruz . Alternatif olarak, thread nesnesine bir referansımız varsa, doğrudan ondan da öğrenebiliriz. Bu, gerekli yapılandırılabilirlik düzeyini sağlar.

31. Bir iş parçacığını oluşturulduktan sonra arka plan programı yapmak mümkün müdür?

Hayır. Bunu yapmaya çalışırsanız, bir IllegalThreadStateException alırsınız . Bu, yalnızca başlamadan önce bir arka plan programı dizisi oluşturabileceğimiz anlamına gelir. Örnek:

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);
   }
}
Konsol çıktısı:
Çalışıyor... Java.lang.Thread.setDaemon(Thread.java:1359) adresindeki "main" java.lang.IllegalThreadStateException dizisindeki istisna SetDaemonAfterStartExample.main(SetDaemonAfterStartExample.java:14) adresinde

32. Kapatma kancası nedir?

Kapatma kancası, Java sanal makinesi (JVM) kapatılmadan önce dolaylı olarak çağrılan bir iş parçacığıdır. Böylece, Java sanal makinesi normal veya anormal bir şekilde kapandığında bir kaynağı serbest bırakmak veya durumu kaydetmek için kullanabiliriz. Aşağıdaki yöntemi kullanarak bir kapatma kancası ekleyebiliriz :

Runtime.getRuntime().addShutdownHook(new ShutdownHookThreadExample());
Örnekte gösterildiği gibi:

/**
* 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();
       }
   }
}
Konsol çıktısı:
Şimdi program uykuya dalacak. Sonlandırmak için Ctrl+C tuşlarına basın. kapatma kancası çalıştırıldı

33. Senkronizasyon nedir?

Java'da senkronizasyon, birden çok iş parçacığının herhangi bir paylaşılan kaynağa erişimini kontrol etme yeteneğidir. Birden çok iş parçacığı aynı görevi aynı anda gerçekleştirmeye çalıştığında, yanlış bir sonuç alabilirsiniz. Bu sorunu çözmek için Java, aynı anda yalnızca bir iş parçacığının çalışmasına izin veren senkronizasyonu kullanır. Senkronizasyon üç şekilde sağlanabilir:
  • Bir yöntemi senkronize etme
  • Belirli bir bloğu senkronize etme
  • statik senkronizasyon

Bir yöntemi senkronize etme

Herhangi bir paylaşılan kaynak için bir nesneyi kilitlemek üzere senkronize edilmiş bir yöntem kullanılır. Bir iş parçacığı senkronize edilmiş bir yöntemi çağırdığında, otomatik olarak nesnenin kilidini alır ve iş parçacığı görevini tamamladığında onu serbest bırakır. Bunun işe yaraması için synchronized anahtar sözcüğünü eklemeniz gerekir . Bunun nasıl çalıştığını bir örneğe bakarak görebiliriz:

/**
* 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);
   }
}
Ve konsol çıktısı şudur:
I Thread-0 Mektup Yazıyorum Iplik Yazmıyorum-1 Mektup Yazmıyorum

senkronizasyon bloğu

Bir senkronize blok, bir yöntemdeki herhangi bir özel kaynak üzerinde senkronizasyon gerçekleştirmek için kullanılabilir. Diyelim ki büyük bir yöntemde (evet, onları yazmamalısınız ama bazen oluyorlar) bir nedenden dolayı yalnızca küçük bir bölümü senkronize etmeniz gerekiyor. Metodun tüm kodunu senkronize edilmiş bir bloğa koyarsanız, senkronize edilmiş bir metotla aynı şekilde çalışacaktır. Sözdizimi şöyle görünür:

synchronized ("object to be locked") {
   // The code that must be protected
}
Önceki örneği tekrarlamaktan kaçınmak için, anonim sınıfları kullanarak iş parçacıkları oluşturacağız, yani Runnable arabirimini hemen uygulayacağız.

/**
* 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();
   }
}

}
Ve konsol çıktısı şudur:
Ben Yazarım1 Mektup Yazarım Yazmam2 Mektup Yazmam

statik senkronizasyon

Statik bir yöntemi senkronize ederseniz, kilitleme nesnede değil sınıfta gerçekleşir. Bu örnekte, synchronized anahtar kelimesini statik bir yönteme uygulayarak statik senkronizasyon gerçekleştiriyoruz:

/**
* 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();
   }
}
Ve konsol çıktısı şudur:
Ben Yazmam2 Mektup Yazmam Ben Yazar1 Mektup Yazarım

34. Uçucu değişken nedir?

Çok iş parçacıklı programlamada, iş parçacığı güvenliği için volatile anahtar sözcüğü kullanılır. Değişken bir değişken değiştirildiğinde, değişiklik diğer tüm iş parçacıkları tarafından görülebilir, böylece bir değişken aynı anda bir iş parçacığı tarafından kullanılabilir. volatile anahtar sözcüğünü kullanarak , bir değişkenin iş parçacığı için güvenli olduğunu ve paylaşılan bellekte saklandığını ve iş parçacıklarının onu önbelleklerinde saklamayacağını garanti edebilirsiniz. Bu neye benziyor?

private volatile AtomicInteger count;
Değişkene sadece volatile ekliyoruz . Ancak bunun tam iş parçacığı güvenliği anlamına gelmediğini unutmayın... Sonuçta, değişken üzerindeki işlemler atomik olmayabilir. Bununla birlikte, işlemleri atomik olarak, yani tek bir CPU talimatında yapan Atomik sınıfları kullanabilirsiniz . Java.util.concurrent.atomic paketinde bu tür birçok sınıf vardır .

35. Kilitlenme nedir?

Java'da kilitlenme, çoklu iş parçacığının bir parçası olarak meydana gelebilecek bir şeydir. Bir iş parçacığı, başka bir iş parçacığı tarafından alınan bir nesnenin kilidini beklerken ve ikinci iş parçacığı, birinci iş parçacığı tarafından alınan nesnenin kilidini beklerken bir kilitlenme meydana gelebilir. Bu, iki iş parçacığının birbirini beklediği ve kodlarının yürütülmesine devam edilemeyeceği anlamına gelir. Java Core için en iyi 50 iş görüşmesi sorusu ve yanıtı.  Bölüm 2 - 4Runnable'ı uygulayan bir sınıfa sahip bir örneği ele alalım. Yapıcısı iki kaynak alır. run() yöntemi, kilidi onlar için sırayla alır. Bu sınıftan iki nesne oluşturursanız ve kaynakları farklı bir sırayla geçirirseniz, o zaman kolayca kilitlenme yaşayabilirsiniz:

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);
           }
       }
   }
}
Konsol çıktısı:
İlk iş parçacığı ilk kaynağı aldı İkinci iş parçacığı ikinci kaynağı aldı

36. Çıkmazdan nasıl kaçınırsınız?

Kilitlenmenin nasıl meydana geldiğini bildiğimiz için bazı sonuçlar çıkarabiliriz...
  • Yukarıdaki örnekte, iç içe kilitlemeye sahip olmamız nedeniyle kilitlenme meydana gelir. Yani, senkronize bir bloğun içinde senkronize bir bloğumuz var. Bunu önlemek için iç içe geçirmek yerine yeni bir daha yüksek soyutlama katmanı oluşturmanız, senkronizasyonu bir üst düzeye taşımanız ve iç içe kilitlemeyi ortadan kaldırmanız gerekir.
  • Ne kadar çok kilitleme yaparsanız, kilitlenme olasılığı o kadar artar. Bu nedenle, her senkronize blok eklediğinizde, buna gerçekten ihtiyacınız olup olmadığını ve yeni bir tane eklemekten kaçınıp kaçınamayacağınızı düşünmeniz gerekir.
  • Thread.join() kullanma . Ayrıca bir iş parçacığı diğerini beklerken kilitlenme yaşayabilirsiniz. Bu sorunu önlemek için, join() yöntemi için bir zaman aşımı ayarlamayı düşünebilirsiniz .
  • Bir iş parçacığımız varsa, kilitlenme olmaz;)

37. Yarış koşulu nedir?

Gerçek hayattaki yarışlar arabaları içeriyorsa, çoklu kullanımdaki yarışlar iş parçacıklarını içerir. Ama neden? :/ Çalışan ve aynı nesneye erişebilen iki iş parçacığı var. Ve aynı anda paylaşılan nesnenin durumunu güncellemeye çalışabilirler. Buraya kadar her şey açık değil mi? İş parçacıkları ya tam anlamıyla paralel olarak (işlemcinin birden fazla çekirdeği varsa) ya da işlemci serpiştirilmiş zaman dilimlerini ayırarak sırayla yürütülür. Bu süreçleri yönetemiyoruz. Bunun anlamı, bir iş parçacığı bir nesneden veri okuduğunda, başka bir iş parçacığı bunu yapmadan ÖNCE nesneyi değiştirmek için zamanı olacağını garanti edemeyiz. Bu tür sorunlar, bu "kontrol et ve harekete geç" kombinasyonlarına sahip olduğumuzda ortaya çıkar. Bu ne anlama gelir? Gövdesi if-koşulunun kendisini değiştiren bir if ifademiz olduğunu varsayalım , örneğin:

int z = 0;

// Check
if (z < 5) {
// Act
   z = z + 5;
}
İki iş parçacığı, z hala sıfırken bu kod bloğuna aynı anda girebilir ve ardından her iki iş parçacığı da değerini değiştirebilir. Sonuç olarak, beklenen 5 değerini alamayacağız. Bunun yerine 10 alacağız. Bundan nasıl kaçınırsınız? Kontrol etmeden ve harekete geçmeden önce bir kilit edinmeniz ve ardından kilidi serbest bırakmanız gerekir. Yani, ilk iş parçacığının if bloğuna girmesini , tüm eylemleri gerçekleştirmesini, z'yi değiştirmesini ve ancak o zaman bir sonraki iş parçacığına aynısını yapma fırsatı vermeniz gerekir. Ancak bir sonraki iş parçacığı , z artık 5 olacağından if bloğuna girmeyecektir :

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

Bir sonuç yerine

Sonuna kadar okuyan herkese teşekkür etmek istiyorum. Uzun bir yoldu, ama dayandın! Belki her şey net değildir. Bu normal. Java çalışmaya ilk başladığımda, beynimi statik bir değişkenin ne olduğu etrafında toplayamadım. Ama önemli değil. Üzerine yattım, birkaç kaynak daha okudum ve sonra anlayış geldi. Mülakata hazırlanmak pratik olmaktan çok akademik bir sorudur. Sonuç olarak, her görüşmeden önce, çok sık kullanmayabileceğiniz şeyleri gözden geçirmeli ve hafızanızda tazelemelisiniz.

Ve her zaman olduğu gibi, işte bazı yararlı bağlantılar:

Herkese okuduğu için teşekkürler. Yakında görüşürüz :) GitHub profilimJava Core için en iyi 50 iş görüşmesi sorusu ve yanıtı.  Bölüm 2 - 5
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION