Java näide loengust
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); } }