Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Join, interrupt i volatile

Join

Un join fa que un fil s’esperi a la finalització d’un altre. El fil que fa el join passa a l’estat WAITING fins que el fil que s’espera acaba. Si el fil que s’espera ja ha acabat, el join no fa res.

public class JoinThread {
	static class MyRunnable implements Runnable {
		@Override
		public void run() {
			log("starting");
			spend(1500);
			log("ending");
		}		
	}	
	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new MyRunnable(), "child");
		log("starting");
		thread.start();
		log("started");
		thread.join();
		log("joined");
	}
}

Interrupt

Una interrupció és una indicació a un fil de què ha de parar de fer el que està fent i fer una altra cosa. Els fils tenen un flag que indica si han estat interromputs o no. Hi ha dues formes de comprovar si un fil ha estat interromput:

  • Que el fil faci crides freqüents a mètodes que facin throw de InterruptedException. Per exemple, Thread.sleep(). També serveix si la interrupció s’ha produït abans del sleep().
  • Que el fil comprovi freqüentment Thread.currentThread().isInterrupted().

Un cop feta la comprovació i detectada la interrupció, el flag d’interrupció del fil es retorna a false i cal decidir què fer. Normalment, el que farà és acabar la seva execució, però no és obligatori. Si no es fa res, el fil continuarà executant-se.

public class Interrupt1Thread {
	static class MyRunnable implements Runnable {
		@Override
		public void run() {
			log("starting");
			try {
				Thread.sleep(1500);
			} catch (InterruptedException e) {
				log("interrupted!");
			}
			log("ending");
		}		
	}
	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new MyRunnable(), "child");
		log("starting");
		thread.start();
		log("started");
		thread.interrupt();		
		thread.join();
		log("joined");
	}
}
public class Interrupt2Thread {
	static class MyRunnable implements Runnable {
		@Override
		public void run() {
			log("starting");
			while (!Thread.currentThread().isInterrupted());
			log("ending");
		}		
	}	
	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new MyRunnable(), "child");
		log("starting");
		thread.start();
		log("started");
		rest(1500);
		thread.interrupt();		
		thread.join();
		log("joined");
	}
}

Estat compartit

Es pot acabar un fil compartint una variable que un fil modifica i l’altre llegeix. En Java, cal definir la variable com a volatile, indicant que els canvis fets en un fil siguin visibles en la resta. O bé utilitzar objectes segurs creats per nosaltres (mecanismes de sincronització) o d’una llibreria segura (p. ex. la atomic de Java).

La paraula clau volatile només s’ha d’utilitzar si un fil escriu i l’altre (o altres) llegeixen. Si diversos fils escriuen i llegeixen, cal gestionar-ho com a zones crítiques.

public class VolatileThread {

	static class SharedObject {
		boolean done; // volatile keyword needed
	}
	
	static class MyRunnable1 implements Runnable {
		SharedObject so;		
		MyRunnable1(SharedObject so) {
			this.so = so;
		}		
		@Override
		public void run() {
			spend(1500);
			so.done = true;
		}
	}
	
	static class MyRunnable2 implements Runnable {		
		SharedObject so;		
		MyRunnable2(SharedObject so) {
			this.so = so;
		}		
		@Override
		public void run() {
			boolean done = false;
			while (!done) {
				done = so.done;
			}
		}
	}
	
	public static void main(String[] args) throws InterruptedException {		
		SharedObject so = new SharedObject();		
		Thread t1 = new Thread(new MyRunnable1(so));
		Thread t2 = new Thread(new MyRunnable2(so));
		t1.start();
		t2.start();		
		t1.join();
		log("joined 1 with " + so.done);
		t2.join();
		log("joined 2 with " + so.done);
	}
}
Last change: , commit: 1ebfee4