JavaRush /Java Blog /Random-IT /Pausa caffè #112. Come dichiarare, inizializzare e scorre...

Pausa caffè #112. Come dichiarare, inizializzare e scorrere un array in Java. Come interrompere un thread Java senza utilizzare Thread.stop()?

Pubblicato nel gruppo Random-IT

Come dichiarare, inizializzare e scorrere un array in Java

Fonte: FreeCodeCamp In questo articolo parleremo degli array in Java. Considereremo alcuni esempi per aiutarti a capire cos'è un array, come dichiararlo e come utilizzarlo nel codice Java. Pausa caffè #112.  Come dichiarare, inizializzare e scorrere un array in Java.  Come interrompere un thread Java senza utilizzare Thread.stop()?  -1

Cos'è un array?

In Java utilizziamo un array per memorizzare più valori dello stesso tipo di dati in un'unica variabile. Può anche essere pensato come una raccolta di valori dello stesso tipo di dati. Ciò significa che se, ad esempio, memorizzerai stringhe nel tuo array, tutti i valori nel tuo array devono essere stringhe.

Come dichiarare un array in Java

Usiamo le parentesi quadre [] per dichiarare un array . Come quello:
String[] names;
Qui abbiamo dichiarato una variabile chiamata nomi che conterrà un array di stringhe. Se dobbiamo dichiarare una variabile per numeri interi (interi), lo faremo in questo modo:
int[] myIntegers;
Quindi, per creare un array, specifichiamo il tipo di dati che verranno archiviati nell'array, seguito da parentesi quadre e quindi dal nome dell'array.

Come inizializzare un array in Java

Inizializzare un array significa assegnare valori all'array. Inizializziamo gli array che abbiamo dichiarato nella sezione precedente:
String[] names = {"John", "Jade", "Love", "Allen"};
int[] myIntegers = {10, 11, 12};
Abbiamo inizializzato i nostri array passando valori dello stesso tipo di dati, separando ogni valore con una virgola. Se volessimo accedere agli elementi/valori nel nostro array, accederemmo al loro numero di indice nell'array. L'indice del primo elemento è 0. Ecco un esempio:
String[] names = {"John", "Jade", "Love", "Allen"};

System.out.println(names[0]);
// John

System.out.println(names[1]);
// Jade

System.out.println(names[2]);
// Love

System.out.println(names[3]);
// Allen
Ora che sappiamo come accedere a ciascun elemento, modifichiamo il valore del terzo elemento.
String[] names = {"John", "Jade", "Love", "Allen"};
names[2] = "Victor";

System.out.println(names[2]);
// Victor
Possiamo anche controllare la lunghezza di un array usando la proprietà length . Ecco un esempio:
String[] names = {"John", "Jade", "Love", "Allen"};
System.out.println(names.length);
// 4

Come scorrere un array in Java

Possiamo usare un ciclo for per scorrere gli elementi di un array .
String[] names = {"John", "Jade", "Love", "Allen"};
for (int i = 0; i < names.length; i++) {
  System.out.println(names[i]);
}

// John
// Jade
// Love
// Allen
Il ciclo sopra stamperà gli elementi del nostro array. Abbiamo utilizzato la proprietà length per specificare quante volte deve essere eseguito il ciclo.

Conclusione

In questo articolo abbiamo imparato come dichiarare e inizializzare gli array nel codice Java. Abbiamo anche visto come accedere a ciascun elemento di un array e come scorrere tali elementi. Buona programmazione!

Come interrompere un thread Java senza utilizzare Thread.stop()?

Fonte: 4comprehension Se stai leggendo questo, probabilmente ti starai chiedendo perché e, soprattutto, come fermare un thread se non puoi semplicemente fare affidamento sul metodo Thread#stop() , che è stato deprecato da Java 1.2 ? Pausa caffè #112.  Come dichiarare, inizializzare e scorrere un array in Java.  Come interrompere un thread Java senza utilizzare Thread.stop()?  - 2La risposta breve è che dovresti usare le interruzioni perché Thread#stop non è sicuro. Ma se vuoi capire perché, come e a cosa serve quella fastidiosa InterruptedException , continua a leggere.

Problema con il thread#stop()

Non importa quanto possa sembrare intuitivo, interrompere un thread già in esecuzione, avviarlo e interromperlo sono due casi completamente diversi. Perché? Quando iniziamo un nuovo thread, iniziamo da zero, che è uno stato ben definito, ma quando proviamo a interrompere un thread esistente, ciò potrebbe accadere nel mezzo di un'operazione che non può essere interrotta immediatamente . Immagina un thread che apporta modifiche a una struttura dati thread-safe. Mentre è nel mezzo della sezione critica... e poi il thread scompare magicamente - i blocchi vengono rilasciati e ora un altro thread può osservare la struttura dei dati lasciata in uno stato incoerente. Considera il seguente esempio di contatore thread-safe con uno stato interno:
class ThreadSafeCounter {

    private volatile int counter = 0;
    private volatile boolean dirty = false;

    public synchronized int incrementAndGet() {
        if (dirty) {
            throw new IllegalStateException("this should never happen");
        }
        dirty = true;
        // ...
        Thread.sleep(5000); // boilerplate not included
        // ...
        counter = counter + 1;
        dirty = false;
        return counter;
    }
}
Come puoi vedere, il metodo getAndIncrement() incrementa il contatore e modifica il flag sporco . I blocchi assicurano che ogni volta che un thread immette getAndIncrement() il flag dirty sia impostato su false . Ora creiamo un thread e interrompiamolo bruscamente:
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (true) {
        threadSafeCounter.incrementAndGet();
    }
});

t1.start();
Thread.sleep(500);
t1.stop();

threadSafeCounter.incrementAndGet();

// Exception in thread "main" java.lang.IllegalStateException: this should never happen
Ora l' istanza threadSafeCounter , nonostante sia stata implementata correttamente, è permanentemente danneggiata a causa dell'interruzione improvvisa del thread. Come sistemarlo?

Interruzione del thread cooperativo

Invece di fermare il thread, dovremmo fare affidamento sull’interruzione cooperativa del thread. In poche parole, dobbiamo chiedere al thread di interrompersi al momento giusto utilizzando Thread#interrupt . Tuttavia, chiamare Thread#interrupt invece di Thread#stop non è sufficiente. La terminazione sicura di un thread può essere ottenuta solo utilizzando un'interruzione del thread condivisa, il che significa che all'interno del thread dobbiamo gestire i segnali di interruzione, che sono di due tipi:
  • Flag booleano interrotto

  • InterruptedException

Gestione dei flag interrompibili

All'interno di un thread possiamo verificare se è stato interrotto richiamando uno dei metodi:
Thread.currentThread().isInterrupted(); // reads the interrupted flag
Thread.interrupted(); // reads and resets the interrupted flag
Poiché non esiste un modo universale per gestire un'interruzione, dobbiamo applicare un'azione adatta al nostro contesto. Nell'esempio della sezione precedente, il thread incrementa il nostro contatore in un ciclo infinito. Invece di fermarci immediatamente, potremmo semplicemente aspettare che il thread completi il ​​suo lavoro ascendente e poi uscire dal ciclo:
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (!Thread.interrupted()) {
        threadSafeCounter.incrementAndGet();
    }
});

t1.start();
Thread.sleep(500);
t1.interrupt();

threadSafeCounter.incrementAndGet();
Ora il thread termina in modo sicuro al momento giusto senza causare caos.

Gestione dell'eccezione interrotta

Cosa succede se proviamo a interrompere un thread in attesa? Naturalmente non possiamo tenere conto del flag di interruzione perché il thread è impegnato in un'operazione di blocco. Ecco perché esiste InterruptedException . Questa non è un'eccezione standard, ma una diversa forma di segnale di interruzione che esiste esclusivamente per gestire gli interrupt bloccanti! Come Thread#interrupted , reimposta il flag di interruzione . Cambiamo nuovamente l'esempio sopra e introduciamo delle pause prima di ogni incremento. Ora dobbiamo gestire l'InterruptedException lanciata da Thread#sleep :
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (!Thread.interrupted()) {
        threadSafeCounter.incrementAndGet();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            break;
        }
    }
});

t1.start();
Thread.sleep(500);
t1.interrupt();

assertThat(threadSafeCounter.incrementAndGet()).isGreaterThan(0);
Nel nostro caso è bastato semplicemente uscire dal giro. Ma cosa succede se non pensi che un metodo specifico dovrebbe essere responsabile della gestione degli interrupt? cosa succede se la firma del metodo non può essere modificata? In questo caso, dobbiamo ripristinare il flag di interruzione e/o riconfezionare l'eccezione, ad esempio:
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new RuntimeException(e);
}

Conclusione:

  • Thread#stop non è deprecato senza motivo: in realtà è molto insicuro.

  • I thread vengono interrotti tramite interruzioni: segnali interpretati dal thread stesso.

  • InterruptedException non è un'eccezione ordinaria: è il modo integrato di Java di segnalare che un thread è stato interrotto.

  • Thread.currentThread().isInterrupted() e Thread.interrupted() non sono la stessa cosa. Il primo legge semplicemente il flag di interruzione e l'altro lo ripristina successivamente.

  • Non esiste un modo universale per gestire i segnali di interruzione: "dipende dalle circostanze".

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION