JavaRush /Java Blog /Random-IT /Traduzione: le 50 principali domande dell'intervista per ...
KapChook
Livello 19
Volga

Traduzione: le 50 principali domande dell'intervista per thread. Parte 2.

Pubblicato nel gruppo Random-IT
La seconda parte della traduzione dell'articolo originale Le 50 principali domande di intervista sui thread Java Risposte per principianti ed esperti programmatori. Prima parte.
  1. Come verificare se un thread mantiene un blocco?

  2. Non avevo idea che si potesse verificare se un thread era attualmente bloccato finché non mi sono imbattuto in questa domanda in un'intervista telefonica. java.lang.Thread ha un metodo holdLock(), restituisce true se e solo se il thread corrente mantiene il monitor su un oggetto specifico.
  3. Come ottenere un dump del thread?

  4. Un thread dump ti consente di scoprire cosa sta attualmente facendo un thread. Esistono diversi modi per ottenere un dump del thread, a seconda del sistema operativo. Su Windows puoi usare la combinazione ctrl + Break, su Linux puoi usare il comando kill -3. Puoi anche utilizzare l'utilità jstack; opera sull'id del processo, che puoi trovare utilizzando un'altra utilità jps.
  5. Quale parametro JVM viene utilizzato per controllare la dimensione dello stack del thread?

  6. Questo è uno dei semplici parametri -Xss utilizzati per controllare la dimensione dello stack di un thread in Java.
  7. Differenze tra sincronizzato e ReentrantLock?

  8. Ci sono stati momenti in cui l'unico modo per ottenere la mutua esclusione era tramite la parola chiave sincronizzata, ma presenta diversi svantaggi, come l'impossibilità di estendere il blocco oltre un metodo o un blocco di codice, ecc. Java 5 risolve questo problema fornendo un controllo più granulare tramite l'interfaccia Lock. ReentrantLock è un'implementazione Lock comune che fornisce un Lock con lo stesso comportamento e semantica di base di un monitor implicito, ottenuto utilizzando metodi sincronizzati, ma con funzionalità avanzate.
  9. Dati 3 thread T1, T2 e T3? Come implementare la sequenza T1, T2, T3?

  10. La coerenza può essere ottenuta in molti modi, ma puoi semplicemente utilizzare il metodo join() per avviare un thread quando un altro ha terminato l'esecuzione. Per implementare la sequenza data, è necessario avviare prima l'ultimo thread, quindi chiamare il metodo join() in ordine inverso, ovvero T3 chiama T2.join e T2 chiama T1.join, quindi T1 finirà per primo e T3 per ultimo .
  11. Cosa fa il metodo del rendimento?

  12. Il metodo yield è un modo per chiedere a un thread di rinunciare alla CPU in modo che un altro thread possa essere eseguito. Questo è un metodo statico e garantisce solo che il thread corrente rinuncerà al processore, ma non decide a quale thread verrà eseguita l'esecuzione.
  13. Qual è il livello di concorrenza di ConcurrentHashMap?

  14. ConcurrentHashMap raggiunge la scalabilità e la sicurezza dei thread suddividendo la mappa effettiva in sezioni. Questa separazione viene ottenuta utilizzando un livello di parallelismo. Questo è un parametro facoltativo per il costruttore ConcurrentHashMap e il suo valore predefinito è 16.
  15. Cos'è il semaforo?

  16. Il semaforo è un nuovo tipo di sincronizzatore. Questo è un semaforo con un contatore. Concettualmente, un semaforo controlla un insieme di permessi. Ogni acquire() si blocca, se necessario, prima che il permesso sia disponibile, quindi lo acquisisce. Ogni release() aggiunge un'autorizzazione, potenzialmente rilasciando l'acquirente che blocca. Tuttavia, questo non utilizza oggetti di autorizzazione effettivi; Semaphore memorizza semplicemente il numero di quelli disponibili e agisce di conseguenza. Semaphore viene utilizzato per proteggere risorse costose disponibili in quantità limitate, come una connessione a un database in pool.
  17. Cosa succede se la coda del pool di thread è già piena e invii un'attività?

  18. Se la coda del pool di thread è piena, l'attività inviata verrà "rifiutata". Il metodo send() di ThreadPoolExecutor lancia una RejectedExecutionException, dopo la quale viene chiamato RejectedExecutionHandler.
  19. Differenze tra i metodi send() edexecute() su un pool di thread?

  20. Entrambi i metodi consentono di inviare un'attività a un pool di thread, ma esiste una leggera differenza tra loro. Esegui(comando eseguibile) è definito nell'interfaccia Executor ed esegue l'attività specificata in futuro, ma, cosa più importante, non restituisce nulla. D'altra parte, send() è un metodo sovraccaricato, può accettare attività Runnable e Callable e può restituire un oggetto Future che può essere utilizzato per annullare l'esecuzione e/o attendere il risultato di un calcolo. Questo metodo è definito nell'interfaccia ExecutorService, che eredita dall'interfaccia Executor, e ogni classe del pool di thread, come ThreadPoolExecutor o ScheduledThreadPoolExecutor, eredita questi metodi.
  21. Cos'è un metodo di blocco?

  22. Un metodo di blocco è un metodo che si blocca finché l'attività non viene completata, ad esempio il metodo ServerSocket accetta() si blocca mentre attende la connessione del client. In questo caso, bloccare significa che il controllo non tornerà al metodo chiamante finché il lavoro non sarà completato. D'altra parte, esistono metodi asincroni o non bloccanti che vengono completati prima del completamento dell'attività.
  23. Il filo Swing è sicuro?

  24. In poche parole, no, Swing non è thread-safe, ma devi spiegare cosa intendi con questo, anche se l'intervistatore non te lo chiede. Quando diciamo che Swing non è thread-safe, solitamente ci riferiamo al fatto che si tratta di un componente che non può essere modificato da più thread. Tutte le modifiche ai componenti della GUI devono essere apportate nel thread AWT e Swing fornisce metodi sincroni e asincroni per pianificare tali modifiche.
  25. Differenze tra invokeAndWait e invokeLater?

  26. Si tratta di due metodi API Swing che consentono agli sviluppatori di aggiornare i componenti della GUI dai thread anziché dal thread Event Manager. InvokeAndWait() aggiorna in modo sincrono un componente GUI come una barra di avanzamento; ogni volta che viene effettuato un progresso, la barra deve essere aggiornata per riflettere le modifiche. Se l'avanzamento viene monitorato in un altro thread, è necessario chiamare invokeAndWait() per assegnare al thread Event Dispatcher l'aggiornamento di quel componente. E invokeLater() è una chiamata asincrona per aggiornare i componenti.
  27. Quali metodi API Swing sono thread-safe?

  28. Questa domanda riguarda ancora una volta Swing e la sicurezza dei thread, sebbene i componenti Swing non siano thread-safe, esistono metodi che possono essere chiamati in sicurezza da più thread. So che repaint() e revalidate() sono thread-safe, ma esistono altri metodi su diversi componenti Swing, come i metodi setText() di JTextComponent e insert() e append() di JTextArea.
  29. Come creare oggetti immutabili?

  30. Potrebbe sembrare che questa domanda non abbia nulla a che fare con il multithreading e la concorrenza, ma è così. L'immutabilità aiuta a semplificare il codice parallelo già complesso. Un oggetto immutabile è molto costoso per gli sviluppatori perché può essere propagato senza alcuna sincronizzazione. Sfortunatamente, Java non ha l'annotazione @Immutable, che renderà il tuo oggetto immutabile, per questo gli sviluppatori devono lavorare sodo. Per creare un oggetto immutabile, è necessario seguire le basi: inizializzazione nel costruttore, nessun setter, nessuna fuga di riferimenti, memorizzazione di copie separate di oggetti mutabili.
  31. Cos'è ReadWriteLock?

  32. In generale, ReadWriteLock è il risultato di una tecnica di analisi dei blocchi per migliorare le prestazioni delle applicazioni parallele. Questa è un'interfaccia aggiunta in Java 5. Funziona su una coppia di blocchi correlati, uno per le operazioni di lettura, uno per le operazioni di scrittura. Un blocco del lettore può essere mantenuto simultaneamente da più thread di lettura finché non ci sono più scrittori. Il blocco della scrittura è esclusivo. Se lo desideri, puoi implementare un'interfaccia con il tuo set di regole oppure puoi utilizzare ReentrantReadWriteLock, che supporta un massimo di 65535 blocchi di scrittura ricorsivi e 65535 blocchi di lettura.
  33. Cos'è il giro occupato?

  34. Busy Spin è una tecnica utilizzata dai programmatori per forzare un thread ad attendere in una determinata condizione. A differenza dei metodi tradizionali, wait(), sleep() o yield(), che implicano la cessione del controllo del processore, questo metodo non cede il processore; invece, esegue semplicemente un ciclo vuoto. Perché qualcuno dovrebbe farlo? Per salvare la cache del processore. Sui sistemi multi-core, è possibile che un thread sospeso continui l'esecuzione su un altro core, il che significa una ricostruzione della cache. Per evitare ricostruzioni costose, il programmatore preferisce attendere meno utilizzando la rotazione occupata.
  35. Differenze tra variabili volatili e atomiche?

  36. Questa è una domanda piuttosto interessante, all'inizio le variabili volatili e atomiche sembrano molto simili, ma sono comunque diverse. Una variabile Volatile fornisce una garanzia "accade prima" che una scrittura avverrà prima di qualsiasi scrittura successiva; non garantisce l'atomicità. Ad esempio, l'operazione count++ non diventerà atomica semplicemente perché count è dichiarato volatile. D'altra parte, la classe AtomicInteger fornisce un metodo atomico per eseguire operazioni complesse in modo atomico, ad esempio getAndIncrement() è un sostituto atomico dell'operatore di incremento, può essere utilizzato per incrementare atomicamente il valore corrente di uno. Esistono anche versioni atomiche per altri tipi di dati.
  37. Cosa succede se un thread lancia un'eccezione in un blocco sincronizzato?

  38. Questa è un'altra domanda trabocchetto per i normali programmatori Java. Non importa come si esce da un blocco sincronizzato, normalmente terminando l'esecuzione o improvvisamente lanciando un'eccezione, il thread rilascia il blocco acquisito quando entra nel blocco sincronizzato. Questo è uno dei motivi per cui preferisco un blocco di blocco sincronizzato a un'interfaccia che richiede particolare attenzione durante il rilascio del blocco, solitamente ottenuto rilasciando il blocco in un blocco finale.
  39. Cos'è la chiusura a doppio controllo di Singleton?

  40. Questa è una delle domande più popolari nei colloqui di lavoro e tuttavia, nonostante la sua popolarità, le probabilità che un candidato risponda sono al massimo del 50%. Metà delle volte non riescono a scrivere il codice e l'altra metà a spiegare come è stato danneggiato e corretto in Java 1.5. Questo è un vecchio modo di creare un singleton thread-safe che tenta di ottimizzare le prestazioni bloccandosi solo quando l'istanza del singleton viene istanziata per la prima volta, ma a causa della complessità e del fatto che era rotto in JDK 1.4, personalmente non mi piace Esso. Tuttavia, anche se non preferisci questo approccio, è utile conoscerlo dal punto di vista del colloquio.
  41. Come creare un Singleton thread-safe?

  42. Questa domanda integra la precedente. Se dici che non ti piace il doppio controllo del blocco, l'intervistatore sarà costretto a chiedere modi alternativi per creare un Singleton thread-safe. E lo sono, puoi sfruttare le funzionalità di caricamento delle classi e di inizializzazione delle variabili statiche per creare un'istanza di Singleton oppure puoi sfruttare il potente tipo enum.
  43. Elenca 3 usanze che segui nella programmazione parallela?

  44. Questa è la mia domanda preferita perché credo che ci siano alcune regole da seguire quando si scrive codice parallelo, il che aiuta con prestazioni, debug e supporto. Di seguito sono elencate le 3 migliori regole che credo che ogni programmatore Java dovrebbe seguire:
    • Dai sempre nomi significativi ai tuoi thread
    • Trovare un bug o rintracciare un'eccezione nel codice parallelo è un compito piuttosto difficile. OrderProcessor, QuoteProcessor o TradeProcessor sono molto migliori di Thread-1. Discussione-2 e Discussione-3. Il nome dovrebbe riflettere l'attività eseguita dal thread. Tutti i principali framework e persino JDK seguono questa regola.
    • Evitare di bloccare o ridurre l'ambito della sincronizzazione
    • Il blocco è costoso e il cambio di contesto è ancora più costoso. Cerca di evitare il più possibile la sincronizzazione e il blocco e ridurrai la sezione critica al minimo richiesto. Questo è il motivo per cui preferisco un blocco temporizzato rispetto a un metodo temporizzato perché ti dà il controllo assoluto sull'entità del blocco.
    • Tra sincronizzatori e attendi e avvisa, scegli sincronizzatori
    • In primo luogo, sincronizzatori come CountDownLatch, Semaphore, CyclicBarrier o Exchanger semplificano la codifica. È molto difficile implementare un flusso di controllo complesso utilizzando l'attesa e la notifica. In secondo luogo, queste classi sono scritte e gestite dai migliori del settore e ci sono buone probabilità che vengano ottimizzate o sostituite con un codice migliore nelle future versioni di JDK. Utilizzando le utilità di sincronizzazione di alto livello, ottieni automaticamente tutti questi vantaggi.
    • Tra Raccolta simultanea e Raccolta sincronizzata, scegli Raccolta simultanea
    • Questa è un'altra semplice regola che è facile da seguire e raccogliere i frutti. Le raccolte simultanee sono più scalabili rispetto alle loro controparti sincronizzate, quindi è meglio usarle quando si scrive codice parallelo. Quindi la prossima volta che avrai bisogno di una mappa, pensa a ConcurrentHashMap prima di pensare a Hashtable.
  45. Come forzare l'avvio di un thread?

  46. Questa è una domanda su come forzare l'esecuzione della garbage collection. In breve, assolutamente no, puoi ovviamente fare una query usando System.gc(), ma non garantisce nulla. Non c'è assolutamente alcun modo per forzare l'avvio di un thread in Java, questo è controllato dallo scheduler del thread e Java non fornisce alcuna API per controllarlo. Questa parte di Java è ancora casuale.
  47. Cos'è il framework Fork/Join?

  48. Il framework Fork/Join introdotto in JDK 7 è una potente utility che consente allo sviluppatore di sfruttare i molteplici processori dei server moderni. È progettato per lavori che possono essere scomposti ricorsivamente in piccole particelle. L'obiettivo è utilizzare tutta la potenza di calcolo disponibile per aumentare le prestazioni della tua applicazione. Un vantaggio significativo di questo framework è che utilizza un algoritmo di furto di lavoro (da lavoro - lavoro e ruba - a rubare). I thread di lavoro che hanno esaurito i lavori possono rubare lavori da altri thread che sono ancora occupati.
  49. Qual è la differenza tra le chiamate a wait() e sleep()?

  50. Sebbene sia l'attesa che la sospensione rappresentino una sorta di pausa in un'applicazione Java, sono dispositivi per esigenze diverse. Wait viene utilizzato per la comunicazione del thread interno, cede al blocco se la condizione di attesa è vera e attende la notifica se le azioni di un altro thread rendono falsa la condizione di attesa. D'altra parte, il metodo sleep() rinuncia semplicemente al processore o interrompe l'esecuzione del thread corrente per un periodo di tempo specificato. La chiamata a sleep() non rilascia il blocco mantenuto dal thread corrente.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION