Java näide loengust

Allikas: Lambda

java.util.concurrent annab erinevad juba paralleelseks kasutuseks sobivad klassid:

import java.io.*;
import java.util.concurrent.*;

See klass esindab threadide poolt jagatud ressurssi (keyword synchronized on selgitatud workeri juures).

class SharedState {
	int a;
	int b;
	synchronized void transact(int amount) {
		a = a - 10;
		b = b + 10;
	}
	LinkedBlockingQueue<String> q;
}

Klass Worker teeb 10 ühiku suuruseid transaktsioone muutujate a ja b vahel. Kui selliseid workereid on mitu, tekib oht, et andmed korrumpeeruvad samaaegse lugemise/kirjutamise tõttu. Seepärast on ühise ressursi kasutamine pandud synchronized bloki sisse. Korraga saab sellises blokis (critical section) olla vaid üks thread. Sama käib ka synchronized meetodite kohta.

class Worker extends Thread {
	SharedState ss;
	Worker(SharedState ss) {
		this.ss = ss;
	}
	public void run() {
		System.out.println("started "+getId());
		for(int i=0; i<5000; i++) {
			//ss.transact(10);
			synchronized(ss) {
				ss.a = ss.a - 10;
				ss.b = ss.b + 10;
			}
		}
		System.out.println("finished "+getId());
	}
}

Klass Producer paneb järjekorda elemente juurde. See asub ka jagatud mäluosas, aga seda ei tohi synchronized bloki sisse panna, kuna antud queue implementatsioon juba sisaldab lukustamist. Igasugune lukkude taga ootamine, ise teist lukku kinni hoides on potentsiaalne koht deadlocki tekkimiseks. Consumer kasutab blokkivat meetodit .take(), mis ei returni seni, kuni järjekorda andmed tekivad.

class Producer extends Worker {
	Producer (SharedState ss) {
		super(ss);
	}
	public void run() {
		System.out.println("started "+getId());
		for(int i = 0; i<10; i++) {
			try {
				ss.q.put("tere");
			} catch(InterruptedException e) {
				//		
			}
		}
		System.out.println("finished "+getId());
	}
}

class Consumer extends Worker {
	Consumer (SharedState ss) {
		super(ss);
	}
	public void run() {
		System.out.println("started "+getId());
		for(int i = 0; i<10; i++) {
			try {
				String dummy;
				dummy = ss.q.take();
				System.out.println("Received "+dummy);
			} catch(InterruptedException e) {
				//		
			}
		}
		System.out.println("finished "+getId());
	}
}

Threadide tegemine paralleelsete transaktsioonide (välja kommenteeritud) või producer-consumer mudeli testimiseks.

public class ParaTest {
	public static void main(String [] argv) {
		Worker t1, t2;
		Producer p;
		Consumer c;
		SharedState ss = new SharedState();
		ss.a = 100000;
		ss.b = 0;
		ss.q = new LinkedBlockingQueue<String> ();
		
		p = new Producer(ss);
		c = new Consumer(ss);
//		t1 = new Worker(ss);
//		t2 = new Worker(ss);
		c.start();
		p.start();
//		t1.start();
//		t2.start();
		try {
			p.join();
			c.join();
//			t1.join();
//			t2.join();
		} catch(InterruptedException e) {
			//		
		}
//		System.out.println("a: "+ss.a+" b: "+ss.b);
	}
}