103. Ano ang mga patakaran para sa pagsuri sa mga eksepsiyon sa mana?
Kung naiintindihan ko nang tama ang tanong, nagtatanong sila tungkol sa mga patakaran para sa pagtatrabaho nang may mga pagbubukod sa panahon ng pagmamana, at ang mga ito ay ang mga sumusunod:- Ang isang na-override o ipinatupad na paraan sa isang descendant/implementation ay hindi makakapagtapon ng mga naka-check na exception na mas mataas sa hierarchy kaysa sa mga exception sa superclass/interface na paraan.
public interface Animal {
void voice() throws IOException;
}
Sa pagpapatupad ng interface na ito, hindi kami maaaring magtapon ng mas pangkalahatang itinapon na exception (halimbawa, Exception , Throwable ), ngunit maaari naming palitan ito ng descendant exception, tulad ng FileNotFoundException :
public class Cat implements Animal {
@Override
public void voice() throws FileNotFoundException {
// некоторая реализация
}
}
- Dapat isama ng subclass constructor sa mga throws nito ang lahat ng exception classes na itinapon ng superclass constructor na tinatawag kapag ginawa ang object.
public class Animal {
public Animal() throws ArithmeticException, NullPointerException, IOException {
}
Pagkatapos ay dapat ding ipahiwatig ng tagapagmana ng klase ang mga ito sa constructor:
public class Cat extends Animal {
public Cat() throws ArithmeticException, NullPointerException, IOException {
super();
}
O, tulad ng sa kaso ng mga pamamaraan, maaari mong tukuyin hindi ang parehong mga pagbubukod, ngunit mas pangkalahatan. Sa aming kaso, ito ay sapat na upang tukuyin ang isang mas pangkalahatang pagbubukod - Exception , dahil ito ang karaniwang ninuno ng lahat ng tatlong mga pagbubukod na isinasaalang-alang:
public class Cat extends Animal {
public Cat() throws Exception {
super();
}
104. Maaari ka bang sumulat ng code para sa kung kailan hindi maisasakatuparan ang panghuling bloke?
Una, tandaan natin kung ano ang wakas . Noong nakaraan, tiningnan namin ang mekanismo para sa paghuli ng mga exception: ang try block ay nagbabalangkas sa catching area, habang ang catch block (mga) ay ang code na gagana kapag may itinapon na partikular na exception. Panghuli ay ang pangatlong bloke ng code pagkatapos na sa wakas ay mapapalitan ng catch ngunit hindi eksklusibo sa isa't isa. Ang kakanyahan ng bloke na ito ay palaging gumagana ang code sa loob nito, anuman ang resulta ng pagsubok o paghuli (hindi alintana kung ang isang pagbubukod ay itinapon o hindi). Ang mga kaso ng pagkabigo nito ay napakabihirang at sila ay abnormal. Ang pinakasimpleng kaso ng pagkabigo ay kapag ang System.exit(0) na pamamaraan ay tinawag sa code sa itaas , na nagtatapos sa programa (pinapatay ito):try {
throw new IOException();
} catch (IOException e) {
System.exit(0);
} finally {
System.out.println("Данное сообщение не будет выведенно в консоль");
}
Mayroon ding ilang iba pang mga sitwasyon kung saan sa wakas ay hindi gagana:
- Abnormal na pagwawakas ng program na dulot ng mga kritikal na problema sa system, o ang pagbagsak ng ilang Error na "mag-crash" sa application (isang halimbawa ng error ay maaaring ang parehong StackOwerflowError na nangyayari kapag umapaw ang memorya ng stack).
- Kapag ang deamon thread ay dumaan sa ry...sa wakas ay naharang at kahanay nito ang programa ay nagtatapos. Pagkatapos ng lahat, ang thread ng deamon ay isang thread para sa mga aksyon sa background, iyon ay, ito ay hindi isang priyoridad at sapilitan, at ang application ay hindi maghintay para sa trabaho nito upang matapos.
- Ang pinakakaraniwang infinite loop, sa try or catch , minsan kung saan ang daloy ay mananatili doon magpakailanman:
try { while (true) { } } finally { System.out.println("Данное сообщение не будет выведенно в консоль"); }
105. Sumulat ng isang halimbawa ng paghawak ng maraming exception sa isang catch block
1) Marahil ang tanong ay naitanong nang hindi tama. Sa pagkakaintindi ko, ang tanong na ito ay nangangahulugan ng maraming catches para sa isang bloke ng pagsubok :try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
System.out.print("Упс, у вас упало исключение - " + e);
} catch (IOException e) {
System.out.print("Упс, у вас упало исключение - " + e);
} catch (Exception e) {
System.out.print("Упс, у вас упало исключение - " + e);
}
Kung may naganap na exception sa isang try block , ang mga catch block ay halili na susubukan na saluhin ito mula sa itaas hanggang sa ibaba. Kung ang isang partikular na catch block ay magtagumpay, ito ay magkakaroon ng karapatang pangasiwaan ang exception, habang ang iba pang mga block sa ibaba ay hindi na magiging kayang subukang hulihin ito at iproseso sa sarili nilang paraan. Samakatuwid, ang mas makitid na mga eksepsiyon ay inilalagay nang mas mataas sa catch block chain, at ang mas malawak na mga exception ay inilalagay na mas mababa. Halimbawa, kung sa aming unang catch block ay nahuli ang isang exception ng Exception class , ang mga nasuri na exception ay hindi makakapasok sa mga natitirang block (ang natitirang mga block na may Exception descendants ay ganap na walang silbi). 2) Ang tanong ay naitanong nang tama. Sa kasong ito, ang aming pagproseso ay magiging ganito ang hitsura:
try {
throw new NullPointerException();
} catch (Exception e) {
if (e instanceof FileNotFoundException) {
// некоторая обработка с сужением типа (FileNotFoundException)e
} else if (e instanceof ArithmeticException) {
// некоторая обработка с сужением типа (ArithmeticException)e
} else if(e instanceof NullPointerException) {
// некоторая обработка с сужением типа (NullPointerException)e
}
Ang pagkakaroon ng nahuli ng isang exception sa pamamagitan ng catch , sinusubukan naming alamin ang partikular na uri nito sa pamamagitan ng instanceof method , na ginagamit upang suriin kung ang isang bagay ay kabilang sa isang tiyak na uri, upang sa ibang pagkakataon ay maaari naming paliitin ito sa ganitong uri nang walang negatibong kahihinatnan. Ang parehong isinasaalang-alang na mga diskarte ay maaaring gamitin sa parehong sitwasyon, ngunit sinabi ko na ang tanong ay hindi tama dahil hindi ko tatawagin ang pangalawang opsyon na mabuti at hindi ko nakita ito sa aking pagsasanay, habang sa parehong oras ang unang pamamaraan na may multicatches ay nakatanggap ng laganap. pansin, kumakalat.
106. Aling operator ang nagpapahintulot sa iyo na pilitin ang isang exception na ihagis? Sumulat ng isang halimbawa
Nagamit ko na ito ng ilang beses sa itaas, ngunit gayunpaman ay uulitin ko ang keyword na ito - throw . Halimbawa ng paggamit (pagpipilit ng pagbubukod):throw new NullPointerException();
107. Maaari bang ang pangunahing pamamaraan ay magtapon ng isang pagbubukod ng throws? Kung gayon, saan ito ililipat?
Una sa lahat, nais kong tandaan na ang pangunahing ay hindi higit sa isang regular na pamamaraan, at oo, tinawag ito ng virtual machine upang simulan ang pagpapatupad ng programa, ngunit bukod dito, maaari itong tawagan mula sa anumang iba pang code. Iyon ay, napapailalim din ito sa karaniwang mga panuntunan para sa pagtukoy ng mga naka-check na pagbubukod pagkatapos ng mga throw :public static void main(String[] args) throws IOException {
Alinsunod dito, ang mga pagbubukod ay maaari ding mangyari dito. Kung ang pangunahing ay hindi tinawag sa ilang paraan, ngunit sinimulan bilang isang punto ng paglulunsad ng programa, kung gayon ang pagbubukod na inihagis nito ay hahawakan ng .UncaughtExceptionHandler interceptor . Ang handler na ito ay isa sa bawat thread (iyon ay, isang handler sa bawat thread). Kung kinakailangan, maaari kang lumikha ng iyong sariling handler at itakda ito gamit ang setDefaultUncaughtExceptionHandler method na tinatawag sa Thread object .
Multithreading
108. Anong mga tool ang alam mo para sa pagtatrabaho sa multithreading?
Basic/Basic Tools para sa Paggamit ng Multithreading sa Java:- Ang naka-synchronize ay isang mekanismo para sa pagsasara (pag-block) ng isang paraan/block kapag ang isang thread ay pumasok dito, mula sa iba pang mga thread.
- Ang pabagu-bago ng isip ay isang mekanismo para sa pagtiyak ng pare-parehong pag-access sa isang variable ng iba't ibang mga thread, iyon ay, sa pagkakaroon ng modifier na ito sa isang variable, ang lahat ng mga pagpapatakbo ng pagtatalaga at pagbabasa ay dapat na atomic. Sa madaling salita, hindi kokopyahin ng mga thread ang variable na ito sa kanilang lokal na memorya at babaguhin ito, ngunit babaguhin ang orihinal na halaga nito.
- Ang Runnable ay isang interface na maaaring ipatupad (sa partikular, ang paraan ng pagpapatakbo nito) sa isang partikular na klase:
public class CustomRunnable implements Runnable {
@Override
public void run() {
// некоторая логика
}
}
At sa pagkakaroon ng paglikha ng object ng klase na ito, maaari kang magsimula ng bagong thread sa pamamagitan ng pagtatakda ng object na ito sa constructor ng bagong Thread object at pagtawag nito sa start() method :
Runnable runnable = new CustomRunnable();
new Thread(runnable).start();
Ang paraan ng pagsisimula ay nagpapatakbo ng ipinatupad na run() na pamamaraan sa isang hiwalay na thread.
- Ang thread ay isang klase, na nagmana mula sa kung saan (habang ini-override ang run method ):
public class CustomThread extends Thread {
@Override
public void run() {
// некоторая логика
}
}
At sa pamamagitan ng paglikha ng isang object ng klase na ito at paglulunsad nito gamit ang start() method , sa gayon ay maglulunsad kami ng bagong thread:
new CustomThread().start();
- Ang Concurrency ay isang package na may mga tool para sa pagtatrabaho sa isang multi-threaded na kapaligiran.
- Concurrent Collections - isang set ng mga koleksyon na dalubhasa para sa pagtatrabaho sa isang multi-threaded na kapaligiran.
- Mga Queue - mga espesyal na pila para sa isang multi-threaded na kapaligiran (pagha-block at hindi pagharang).
- Ang mga synchronizer ay mga espesyal na kagamitan para sa pagtatrabaho sa isang multi-threaded na kapaligiran.
- Ang mga tagapagpatupad ay mga mekanismo para sa paglikha ng mga thread pool.
- Mga kandado - mga mekanismo ng pag-synchronize ng thread (mas nababaluktot kaysa sa mga karaniwang - naka-synchronize, maghintay, ipaalam, ipaalam sa Lahat).
- Ang Atomics ay mga klase na na-optimize para sa multi-threaded execution; ang bawat operasyon ay atomic.
109. Pag-usapan ang tungkol sa pag-synchronize sa pagitan ng mga thread. Para saan ang wait(), notify() - notifyAll() join() method?
Sa pagkakaintindi ko sa tanong, ang pag-synchronize sa pagitan ng mga thread ay tungkol sa key modifier - synchronized . Maaaring ilagay ang modifier na ito nang direkta sa tabi ng bloke:synchronized (Main.class) {
// некоторая логика
}
O direkta sa lagda ng pamamaraan:
public synchronized void move() {
// некоторая логика}
Tulad ng sinabi ko kanina, ang naka-synchronize ay isang mekanismo na nagbibigay-daan sa iyo upang isara ang isang bloke/pamamaraan mula sa iba pang mga thread kapag napasok na ito ng isang thread. Isipin ang isang bloke/paraan bilang isang silid. Ang ilang batis, pagdating dito, ay papasok dito at i-lock ito, ang ibang mga batis, pagdating sa silid at makitang sarado ito, ay maghihintay malapit dito hanggang sa ito ay libre. Nang magawa ang negosyo nito, ang unang thread ay umalis sa silid at inilabas ang susi. At hindi para sa wala na patuloy kong pinag-uusapan ang susi, dahil talagang umiiral ito. Ito ay isang espesyal na bagay na may abala/libreng estado. Ang bagay na ito ay naka-attach sa bawat Java object, kaya kapag gumagamit ng isang naka-synchronize na bloke kailangan naming ipahiwatig sa panaklong ang bagay na ang mutex ay gusto naming isara ang pinto sa:
Cat cat = new Cat();
synchronized (cat) {
// некоторая логика
}
Maaari ka ring gumamit ng class mutex, tulad ng ginawa ko sa unang halimbawa ( Main.class ). Kapag gumagamit kami ng naka-synchronize sa isang pamamaraan, hindi namin tinukoy ang bagay na gusto naming isara, tama ba? Sa kasong ito, para sa isang non-static na pamamaraan, isasara nito ang mutex ng object na ito , iyon ay, ang kasalukuyang object ng klase na ito. Ang static ay isasara sa mutex ng kasalukuyang klase ( this.getClass(); ). Maaari kang magbasa ng higit pa tungkol sa mutex dito . Well, basahin ang tungkol sa naka-synchronize dito . Ang Wait() ay isang paraan na naglalabas ng mutex at inilalagay ang kasalukuyang thread sa standby mode, na parang naka-attach sa kasalukuyang monitor (tulad ng anchor). Dahil dito, ang pamamaraang ito ay matatawag lamang mula sa isang naka-synchronize na bloke o pamamaraan (kung hindi man, ano ang dapat na libre at kung ano ang dapat nitong asahan). Tandaan din na ito ay isang paraan ng klase ng Bagay . Mas tiyak, hindi isa, ngunit kahit tatlo:
-
Wait() - inilalagay ang kasalukuyang thread sa wait mode hanggang sa tawagin ng isa pang thread ang notify() o notifyAll() method para sa object na ito (pag-uusapan natin ang mga pamamaraang ito mamaya).
-
Wait (long timeout) - inilalagay ang kasalukuyang thread sa wait mode hanggang sa tawagin ng isa pang thread ang notify() o notifyAll() na paraan sa object na ito o ang tinukoy na timeout ay mag-expire .
-
Maghintay (mahabang timeout, int nanos) - katulad ng nauna, nanos lang ang nagpapahintulot sa iyo na tukuyin ang mga nanosecond (mas tumpak na setting ng oras).
-
Notify() ay isang paraan na nagbibigay-daan sa iyong gisingin ang isang random na thread ng kasalukuyang synchronization block. Muli, maaari lamang itong tawagan sa isang naka-synchronize na bloke o pamamaraan (pagkatapos ng lahat, sa ibang mga lugar ay wala itong sinumang mag-unfreeze).
-
Ang NotifyAll() ay isang paraan na gumigising sa lahat ng naghihintay na mga thread sa kasalukuyang monitor (ginagamit din lamang sa isang naka-synchronize na block o paraan).
110. Paano itigil ang daloy?
Ang unang bagay na sasabihin ay kapag ang run() na pamamaraan ay ganap na naisakatuparan , ang thread ay awtomatikong masisira. Ngunit kung minsan kailangan mong patayin siya nang maaga sa iskedyul, bago makumpleto ang pamamaraang ito. Kaya ano ang dapat nating gawin pagkatapos? Marahil ang bagay na Thread ay dapat magkaroon ng isang stop() na pamamaraan ? Hindi mahalaga kung paano ito ay! Ang pamamaraang ito ay itinuturing na hindi napapanahon at maaaring humantong sa mga pag-crash ng system. Well, ano kung gayon? Mayroong dalawang paraan upang gawin ito: Ang una ay ang paggamit ng iyong panloob na boolean flag. Tingnan natin ang isang halimbawa. Mayroon kaming sariling pagpapatupad ng isang thread na dapat magpakita ng isang partikular na parirala sa screen hanggang sa ganap itong tumigil:public class CustomThread extends Thread {
private boolean isActive;
public CustomThread() {
this.isActive = true;
}
@Override
public void run() {
{
while (isActive) {
System.out.println("Поток выполняет некую логику...");
}
System.out.println("Поток остановлен!");
}
}
public void stopRunningThread() {
isActive = false;
}
}
Kapag ginagamit ang stopRunning() method , nagiging false ang internal flag at hihinto sa pagtakbo ang run method . Patakbuhin natin ito sa pangunahing :
System.out.println("Начало выполнения программы");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// пока наш основной поток спит, вспомогательный CustomThread работает и выводит в коноль своё сообщение
thread.stopRunningThread();
System.out.println("Конец выполнения программы");
Bilang resulta, makakakita tayo ng ganito sa console:
public class CustomThread extends Thread {
@Override
public void run() {
{
while (!Thread.interrupted()) {
System.out.println("Поток выполняет некую логику...");
}
System.out.println("Поток остановлен!");
}
}
}
Tumakbo sa pangunahing :
System.out.println("Начало выполнения программы");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Конец выполнения программы");
Ang resulta ng pagpapatupad ay magiging kapareho ng sa unang kaso, ngunit mas gusto ko ang diskarteng ito: mas kaunting code ang isinulat namin at gumagamit ng mas handa, karaniwang pag-andar. Doon tayo titigil ngayon.
GO TO FULL VERSION