CodeGym /Blog Java /rawak /Meneroka soalan dan jawapan daripada temu duga kerja untu...
John Squirrels
Tahap
San Francisco

Meneroka soalan dan jawapan daripada temu duga kerja untuk jawatan pembangun Java. Bahagian 12

Diterbitkan dalam kumpulan
Hai! Pengetahuan adalah kuasa. Lebih banyak pengetahuan anda dalam temuduga pertama anda, lebih yakin anda akan rasa. Meneroka soalan dan jawapan daripada temu duga kerja untuk jawatan pembangun Java.  Bahagian 12 - 1Jika anda membawa masuk otak besar yang penuh dengan pengetahuan, penemuduga anda akan mendapati sukar untuk mengelirukan anda dan mungkin akan terkejut. Jadi tanpa berlengah lagi, hari ini kami akan terus mengukuhkan asas teori anda dengan menyemak soalan untuk pembangun Java.

103. Apakah peraturan yang digunakan untuk semakan pengecualian semasa pewarisan?

Jika saya memahami soalan dengan betul, mereka bertanya tentang peraturan untuk bekerja dengan pengecualian semasa pewarisan. Peraturan yang berkaitan adalah seperti berikut:
  • Kaedah yang ditindih atau dilaksanakan dalam turunan/pelaksanaan tidak boleh membuang pengecualian yang diperiksa yang lebih tinggi dalam hierarki daripada pengecualian dalam kaedah superclass/antara muka.
Sebagai contoh, katakan kita mempunyai beberapa antara muka Haiwan dengan kaedah yang membuang IOException :

public interface Animal {
   void speak() throws IOException;
}
Apabila melaksanakan antara muka ini, kita tidak boleh mendedahkan pengecualian boleh lempar yang lebih umum (cth Exception , Throwable ), tetapi kita boleh menggantikan pengecualian sedia ada dengan subkelas, seperti FileNotFoundException :

public class Cat implements Animal {
   @Override
   public void speak() throws FileNotFoundException {
// Some implementation
   }
}
  • Klausa lontaran bagi pembina subkelas mesti termasuk semua kelas pengecualian yang dilemparkan oleh pembina kelas super yang dipanggil untuk mencipta objek.
Katakan pembina kelas Haiwan melemparkan banyak pengecualian:

 public class Animal {
   public Animal() throws ArithmeticException, NullPointerException, IOException {
   }
Kemudian pembina subkelas juga mesti membuangnya:

public class Cat extends Animal {
   public Cat() throws ArithmeticException, NullPointerException, IOException {
       super();
   }
Atau, seperti kaedah, anda boleh menentukan pengecualian yang berbeza dan lebih umum. Dalam kes kami, kami boleh menunjukkan Exception , kerana ia lebih umum dan merupakan nenek moyang yang sama bagi ketiga-tiga pengecualian yang ditunjukkan dalam superclass:

public class Cat extends Animal {
   public Cat() throws Exception {
       super();
   }

104. Bolehkah anda menulis beberapa kod di mana blok akhirnya tidak dilaksanakan?

Pertama, mari kita ingat apa yang akhirnya . Terdahulu, kami telah memeriksa mekanisme penangkapan pengecualian: blok cuba menetapkan tempat pengecualian akan ditangkap, dan blok tangkapan ialah kod yang akan digunakan apabila pengecualian yang sepadan ditangkap . Blok ketiga kod yang ditandakan dengan kata kunci akhirnya boleh menggantikan atau datang selepas blok tangkapan. Idea di sebalik blok ini ialah kodnya sentiasa dilaksanakan tanpa mengira apa yang berlaku dalam blok cuba atau tangkap (tidak kira sama ada terdapat pengecualian atau tidak). Kejadian, di mana blok ini tidak dilaksanakan adalah jarang berlaku dan ia tidak normal. Contoh paling mudah ialah apabila System.exit(0) dipanggil sebelum blok akhirnya, dengan itu menamatkan program:

try {
   throw new IOException();
} catch (IOException e) {
   System.exit(0);
} finally {
   System.out.println("This message will not be printed on the console");
}
Terdapat juga beberapa situasi lain di mana blok akhirnya tidak akan dijalankan:
  • Contohnya, penamatan atur cara yang tidak normal yang disebabkan oleh ralat sistem kritikal, atau beberapa ralat yang menyebabkan aplikasi ranap (contohnya, StackOverflowError , yang berlaku apabila timbunan aplikasi dilimpahi).

  • Situasi lain ialah apabila benang daemon memasuki blok cuba-akhir , tetapi kemudian utas utama program ditamatkan. Lagipun, benang daemon adalah untuk kerja latar belakang yang bukan keutamaan tinggi atau wajib, jadi aplikasi tidak akan menunggu untuk selesai.

  • Contoh yang paling tidak masuk akal ialah gelung yang tidak berkesudahan di dalam blok cuba atau tangkap — sekali masuk, benang akan tersangkut di sana selama-lamanya:

    
    try {
       while (true) {
       }
    } finally {
       System.out.println("This message will not be printed on the console");
    }
Soalan ini sangat popular dalam temu bual pembangun junior, jadi adalah idea yang baik untuk mengingati beberapa situasi luar biasa ini. Meneroka soalan dan jawapan daripada temu duga kerja untuk jawatan pembangun Java.  Bahagian 12 - 2

105. Tulis satu contoh di mana anda mengendalikan berbilang pengecualian dalam satu blok tangkapan.

1) Saya tidak pasti soalan ini ditanya dengan betul. Setakat yang saya faham, soalan ini merujuk kepada beberapa blok tangkapan dan satu percubaan :

try {
  throw new FileNotFoundException();
} catch (FileNotFoundException e) {
   System.out.print("Oops! There was an exception: " + e);
} catch (IOException e) {
   System.out.print("Oops! There was an exception: " + e);
} catch (Exception e) {
   System.out.print("Oops! There was an exception: " + e);
}
Jika pengecualian dilemparkan dalam blok percubaan , maka blok tangkapan yang berkaitan cuba menangkapnya, secara berurutan dari atas ke bawah. Setelah pengecualian sepadan dengan salah satu blok tangkapan , mana-mana blok yang tinggal tidak akan dapat menangkap dan mengendalikannya lagi. Ini semua bermakna bahawa pengecualian yang lebih sempit disusun di atas yang lebih umum dalam set blok tangkapan . Sebagai contoh, jika blok tangkapan pertama kami menangkap kelas Pengecualian , maka mana-mana blok berikutnya tidak akan menangkap pengecualian yang diperiksa (iaitu, blok yang tinggal dengan subkelas Pengecualian akan menjadi tidak berguna sama sekali). 2) Atau mungkin soalan itu ditanya dengan betul. Dalam kes itu, kami boleh mengendalikan pengecualian seperti berikut:

try {
  throw new NullPointerException();
} catch (Exception e) {
   if (e instanceof FileNotFoundException) {
       // Some handling that involves a narrowing type conversion: (FileNotFoundException)e
   } else if (e instanceof ArithmeticException) {
       // Some handling that involves a narrowing type conversion: (ArithmeticException)e
   } else if(e instanceof NullPointerException) {
       // Some handling that involves a narrowing type conversion: (NullPointerException)e
   }
Selepas menggunakan tangkapan untuk menangkap pengecualian, kami kemudian cuba menemui jenis khususnya dengan menggunakan pengendali instanceof , yang menyemak sama ada objek tergolong dalam jenis tertentu. Ini membolehkan kami melakukan penukaran jenis penyempitan dengan yakin tanpa rasa takut akan akibat negatif. Kita boleh menggunakan mana-mana pendekatan dalam situasi yang sama. Saya menyatakan keraguan tentang soalan itu hanya kerana saya tidak akan memanggil pilihan kedua sebagai pendekatan yang baik. Dalam pengalaman saya, saya tidak pernah menemuinya, dan pendekatan pertama yang melibatkan berbilang blok tangkapan adalah meluas.

106. Pengendali manakah yang membenarkan anda memaksa pengecualian dilemparkan? Tulis satu contoh

Saya telah menggunakannya beberapa kali dalam contoh di atas, tetapi saya akan mengulanginya sekali lagi: kata kunci lontaran . Contoh melontar pengecualian secara manual:

throw new NullPointerException();

107. Bolehkah kaedah utama membuang pengecualian? Jika ya, maka ke mana ia pergi?

Pertama sekali, saya ingin ambil perhatian bahawa kaedah utama tidak lebih daripada kaedah biasa. Ya, ia dipanggil oleh mesin maya untuk memulakan pelaksanaan program, tetapi di luar itu, ia boleh dipanggil dari mana-mana kod lain. Ini bermakna ia juga tertakluk kepada peraturan biasa tentang menunjukkan pengecualian yang diperiksa selepas kata kunci lontaran :

public static void main(String[] args) throws IOException {
Sehubungan itu, ia boleh membuang pengecualian. Apabila main dipanggil sebagai titik permulaan program (bukan dengan kaedah lain), maka sebarang pengecualian yang dilemparkan akan dikendalikan oleh UncaughtExceptionHandler . Setiap benang mempunyai satu pengendali sedemikian (iaitu, terdapat satu pengendali sedemikian dalam setiap utas). Jika perlu, anda boleh mencipta pengendali anda sendiri dan menetapkannya dengan memanggil public static void main(String[] args) throws IOException {setDefaultUncaughtExceptionHandler method on a public static void main(String[] args) throws IOException {Thread object.

Multithreading

Meneroka soalan dan jawapan daripada temu duga kerja untuk jawatan pembangun Java.  Bahagian 12 - 3

108. Apakah mekanisme untuk bekerja dalam persekitaran berbilang benang yang anda tahu?

Mekanisme asas untuk multithreading di Jawa ialah:
  • Kata kunci yang disegerakkan , yang merupakan cara untuk benang mengunci kaedah/sekat apabila ia masuk, menghalang benang lain daripada masuk.

  • Kata kunci yang tidak menentu memastikan akses yang konsisten kepada pembolehubah yang diakses oleh urutan yang berbeza. Iaitu, apabila pengubah suai ini digunakan pada pembolehubah, semua operasi untuk menetapkan dan membaca pembolehubah itu menjadi atom. Dalam erti kata lain, benang tidak akan menyalin pembolehubah ke memori tempatan mereka dan mengubahnya. Mereka akan menukar nilai asalnya.

  • Runnable — Kami boleh melaksanakan antara muka ini (yang terdiri daripada kaedah run() tunggal ) dalam beberapa kelas:

    
    public class CustomRunnable implements Runnable {
       @Override
       public void run() {
           // Some logic
       }
    }

    Dan sebaik sahaja kami mencipta objek kelas itu, kami boleh memulakan utas baharu dengan menghantar objek kami kepada pembina Thread dan kemudian memanggil kaedah start() :

    
    Runnable runnable = new CustomRunnable();
    new Thread(runnable).start();

    Kaedah mula menjalankan kaedah run() yang dilaksanakan pada benang berasingan.

  • Thread — Kita boleh mewarisi kelas ini dan mengatasi kaedah lariannya :

    
    public class CustomThread extends Thread {
       @Override
       public void run() {
           // Some logic
       }
    }

    Kita boleh memulakan utas baharu dengan mencipta objek kelas ini dan kemudian memanggil kaedah start() :

    
    new CustomThread().start();

  • Concurrency — Ini ialah pakej alatan untuk bekerja dalam persekitaran berbilang benang.

    Ia terdiri daripada:

    • Koleksi Serentak — Ini ialah koleksi koleksi yang dicipta secara eksplisit untuk bekerja dalam persekitaran berbilang benang.

    • Baris gilir — Baris gilir khusus untuk persekitaran berbilang benang (menyekat dan tidak menyekat).

    • Penyegerak — Ini adalah utiliti khusus untuk bekerja dalam persekitaran berbilang benang.

    • Pelaksana — Mekanisme untuk mencipta kumpulan benang.

    • Kunci — Mekanisme penyegerakan benang yang lebih fleksibel daripada yang standard (disegerakkan, tunggu, maklumkan, maklumkanSemua).

    • Atomics — Kelas dioptimumkan untuk multithreading. Setiap operasi mereka adalah atom.

109. Beritahu kami tentang penyegerakan antara utas. Untuk apa kaedah wait(), notify(), notifyAll(), dan join()?

Penyegerakan antara utas adalah mengenai kata kunci yang disegerakkan . Pengubah suai ini boleh diletakkan sama ada secara langsung pada blok:

synchronized (Main.class) {
   // Some logic
}
Atau terus dalam tandatangan kaedah:

public synchronized void move() {
   // Some logic }
Seperti yang saya katakan sebelum ini, disegerakkan ialah mekanisme untuk mengunci blok/kaedah ke benang lain sebaik sahaja satu utas masuk. Mari kita fikirkan blok/kaedah kod sebagai bilik. Beberapa benang menghampiri bilik, memasukinya, dan mengunci pintu dengan kuncinya. Apabila benang lain menghampiri bilik, mereka melihat bahawa pintu dikunci dan menunggu berdekatan sehingga bilik itu tersedia. Setelah benang pertama selesai dengan urusannya di dalam bilik, ia membuka kunci pintu, meninggalkan bilik dan melepaskan kunci. Saya telah menyebut satu kunci beberapa kali atas sebab tertentu — kerana sesuatu yang serupa benar-benar wujud. Ini adalah objek khas yang mempunyai keadaan sibuk/bebas. Setiap objek dalam Java mempunyai objek sedemikian, jadi apabila kita menggunakan blok yang disegerakkan , kita perlu menggunakan kurungan untuk menunjukkan objek yang mutexnya akan dikunci:

Cat cat = new Cat();
synchronized (cat) {
   // Some logic
}
Kita juga boleh menggunakan mutex yang dikaitkan dengan kelas, seperti yang saya lakukan dalam contoh pertama ( Main.class ). Lagipun, apabila kita menggunakan kaedah yang disegerakkan , kita tidak menentukan objek yang ingin dikunci, bukan? Dalam kes ini, untuk kaedah bukan statik, mutex yang akan dikunci ialah objek ini , iaitu objek semasa kelas. Untuk kaedah statik, mutex yang dikaitkan dengan kelas semasa ( this.getClass(); ) dikunci. wait() ialah kaedah yang membebaskan mutex dan meletakkan benang semasa ke dalam keadaan menunggu, seolah-olah melekat pada monitor semasa (sesuatu seperti sauh). Oleh sebab itu, kaedah ini hanya boleh dipanggil dari blok atau kaedah yang disegerakkan . Jika tidak, apa yang akan ia tunggu dan apa yang akan dikeluarkan?). Juga ambil perhatian bahawa ini adalah kaedah kelas Objek . Nah, bukan satu, tetapi tiga:
  • wait() meletakkan benang semasa ke dalam keadaan menunggu sehingga thread lain memanggil kaedah notify() atau notifyAll() pada objek ini (kita akan bercakap tentang kaedah ini kemudian).

  • wait(long timeout) meletakkan utas semasa ke dalam keadaan menunggu sehingga thread lain memanggil kaedah notify() atau notifyAll() pada objek ini atau selang masa yang ditentukan oleh tamat masa tamat.

  • tunggu (masa tamat lama, int nanos) adalah seperti kaedah sebelumnya, tetapi di sini nano membolehkan anda menentukan nanosaat (masa tamat yang lebih tepat).

  • notify() membolehkan anda membangunkan satu utas rawak menunggu pada blok penyegerakan semasa. Sekali lagi, kaedah ini hanya boleh dipanggil dalam blok atau kaedah yang disegerakkan (lagipun, di tempat lain tidak akan ada orang untuk bangun).

  • notifyAll() membangkitkan semua benang yang menunggu pada monitor semasa (juga hanya digunakan dalam blok atau kaedah yang disegerakkan ).

110. Bagaimanakah kita menghentikan benang?

Perkara pertama yang perlu dikatakan di sini ialah apabila run() berjalan hingga selesai, benang ditamatkan secara automatik. Tetapi kadang-kadang kita mahu membunuh benang lebih awal daripada jadual, sebelum kaedah itu dilakukan. Jadi apa yang kita lakukan? Mungkin kita boleh menggunakan kaedah stop() pada objek Thread ? Tidak! Kaedah itu ditamatkan dan boleh menyebabkan ranap sistem. Meneroka soalan dan jawapan daripada temu duga kerja untuk jawatan pembangun Java.  Bahagian 12 - 4Nah, kemudian apa? Terdapat dua cara untuk melakukan ini: Pertama , gunakan bendera boolean dalamannya. Mari kita lihat satu contoh. Kami mempunyai pelaksanaan urutan yang sepatutnya memaparkan frasa tertentu pada skrin sehingga utas itu berhenti sepenuhnya:

public class CustomThread extends Thread {
private boolean isActive;
 
   public CustomThread() {
       this.isActive = true;
   }
 
   @Override
   public void run() {
       {
           while (isActive) {
               System.out.println("The thread is executing some logic...");
           }
           System.out.println("The thread stopped!");
       }
   }
 
   public void stopRunningThread() {
       isActive = false;
   }
}
Memanggil kaedah stopRunningThread() menetapkan bendera dalaman kepada palsu, menyebabkan kaedah run() ditamatkan. Mari kita panggil ia dalam utama :

System.out.println("Program starting...");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// As long as our main thread is asleep, our CustomThread runs and prints its message on the console
thread.stopRunningThread();
System.out.println("Program stopping...");
Akibatnya, kita akan melihat sesuatu seperti ini dalam konsol:
Program bermula... Benang sedang melaksanakan beberapa logik... Benang sedang melaksanakan beberapa logik... Benang sedang melaksanakan beberapa logik... Benang sedang melaksanakan beberapa logik... Benang sedang melaksanakan beberapa logik... Benang sedang melaksanakan beberapa logik... Program berhenti... Benang dihentikan!
Ini bermakna bahawa urutan kami bermula, mencetak beberapa mesej pada konsol, dan kemudian berjaya dihentikan. Ambil perhatian bahawa bilangan mesej yang dipaparkan akan berbeza dari pelancaran ke pelancaran. Dan kadangkala benang tambahan mungkin tidak memaparkan apa-apa sama sekali. Tingkah laku khusus bergantung pada berapa lama benang utama tidur. Semakin lama ia tidur, semakin kecil kemungkinan benang tambahan tidak dapat memaparkan apa-apa. Dengan masa tidur 1 ms, anda hampir tidak akan melihat mesej itu. Tetapi jika anda menetapkannya kepada 20 ms, maka mesej hampir selalu dipaparkan. Apabila masa tidur pendek, benang tidak mempunyai masa untuk memulakan dan melakukan kerjanya. Sebaliknya, ia dihentikan serta-merta. Cara kedua ialah menggunakan kaedah interrupted() pada objek Thread . Ia mengembalikan nilai bendera dalaman yang terganggu, yang palsu secara lalai. Atau kaedah interrupt() nya , yang menetapkan bendera ini kepada true (apabila bendera true , benang harus berhenti berjalan). Mari lihat contoh:

public class CustomThread extends Thread {
 
   @Override
   public void run() {
       {
           while (!Thread.interrupted()) {
               System.out.println("The thread is executing some logic...");
           }
           System.out.println("The thread stopped!");
       }
   }
}
Berjalan di utama :

System.out.println("Program starting...");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Program stopping...");
Hasil daripada menjalankan ini adalah sama seperti dalam kes pertama, tetapi saya lebih suka pendekatan ini: kami menulis kurang kod dan menggunakan lebih banyak kefungsian standard yang sudah siap. Nah, itu sahaja untuk hari ini!
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION