Τμήμα Μηχανικών Πληροφορικής Τ.Ε. Σχολή Τεχνολογικών Εφαρμογών Ακαδημαϊκό έτος 2016-2017 ΤΕΙ Ηπείρου - Άρτα Κατανεμημένα και Παράλληλα Συστήματα (εργαστήριο) Γκόγκος Χρήστος Εκφωνήσεις ασκήσεων εργαστηρίου 2 (java threads) Άσκηση 1 Να γράψετε πρόγραμμα που να δημιουργεί 10 νήματα. Το κάθε νήμα να εμφανίζει έναν τυχαίο ακέραιο αριθμό στο διάστημα [1,100] και να τερματίζει. Όταν ολοκληρώσουν την εκτέλεσή τους όλα τα νήματα να εμφανίζει το μήνυμα «Main thread finished». Γράψτε δύο εκδόσεις του προγράμματος μια στην οποία τα νήματα να υλοποιούν (implements) το interface Runnable και μια που να κληρονομούν (extends) από την κλάση Threads. Άσκηση 2 Να γράψετε πρόγραμμα που να δέχεται ως παράμετρο γραμμής εντολών έναν ακέραιο αριθμό και να εμφανίζει το άθροισμα όλων των θετικών ακεραίων που είναι μικρότεροι ή ίσοι του αριθμού αυτού. Για τον υπολογισμό του αθροίσματος να χρησιμοποιεί νήματα. Ο αριθμός των νημάτων θα περνά επίσης ως παράμετρος γραμμής εντολών. Υπολογίστε το άθροισμα των πρώτων 10.000.000 θετικών ακέραιων αριθμών χρησιμοποιώντας 4 νήματα. Για τον υπολογισμό του συνολικού αθροίσματος να πραγματοποιηθεί συγχρονισμός των νημάτων. (Προαιρετικά: υλοποιήστε το ίδιο πρόγραμμα χρησιμοποιώντας αντί για συγχρονισμό με το synchronized ReentrantLock καθώς και ThreadPool, Callables και Futures) Άσκηση 3 Να γράψετε πρόγραμμα που να γεμίζει με τυχαίες ακέραιες τιμές στο διάστημα [1,10] δύο διανύσματα 1000 θέσεων το καθένα και να υπολογίζει το εσωτερικό τους γινόμενο (http://mathinsight.org/dot_product_matrix_notation). Για τον υπολογισμό του εσωτερικού γινομένου η εργασία να «σπάσει» σε 4 νήματα. Άσκηση 4 Να γράψετε πρόγραμμα που να υλοποιεί ένα σενάριο παραγωγού καταναλωτή με τη χρήση ενός BlockingQueue. Ένα νήμα (παραγωγός) θα παράγει 20 ακέραιες τιμές και θα τις τοποθετεί σε μια ουρά με μήκος 10 και ένα νήμα (καταναλωτής) θα καταναλώνει τις τιμές δημιουργώντας ταυτόχρονα ένα άθροισμα με όλες τις τιμές τις οποίες θα έχει αφαιρέσει από την ουρά. Τόσο η παραγωγή όσο και η κατανάλωση κάθε τιμής θα γίνεται σε τυχαία χρονικά διαστήματα που θα είναι από 0 έως και 2 δευτερόλεπτα για τον παραγωγό ενώ για τον καταναλωτή από 0 έως και 3 δευτερόλεπτα. Άσκηση 5 Να γράψετε πρόγραμμα που να εμφανίζει μια οθόνη swing με ένα πλήκτρο και μια ετικέτα και όταν πατηθεί το πλήκτρο να εμφανίζει και στην κονσόλα αλλά και στην ετικέτα μια αρίθμηση από το 10 μέχρι το 0 όπου για κάθε μείωση του αριθμού να μεσολαβεί 1 δευτερόλεπτο. 1
Λύσεις ασκήσεων Άσκηση 1 import java.util.concurrent.threadlocalrandom; class MyRunnable implements Runnable { int r = ThreadLocalRandom.current().nextInt(1, 101); System.out.printf("Thread %s produced value %d\n", Thread.currentThread().getName(), r); public class Exercise01Runnables { public static void main(string[] args) throws InterruptedException { Thread mythreads[] = new Thread[10]; for (int i = 0; i < 10; i++) { mythreads[i] = new Thread(new MyRunnable()); mythreads[i].start(); for (int i = 0; i < 10; i++) mythreads[i].join(); System.out.println("Main thread finished"); Exercise01Runnables.java import java.util.concurrent.threadlocalrandom; class MyRunnable implements Runnable { int r = ThreadLocalRandom.current().nextInt(1, 101); System.out.printf("Thread %s produced value %d\n", Thread.currentThread().getName(), r); public class Exercise01Runnables { public static void main(string[] args) throws InterruptedException { Thread mythreads[] = new Thread[10]; for (int i = 0; i < 10; i++) { mythreads[i] = new Thread(new MyRunnable()); mythreads[i].start(); for (int i = 0; i < 10; i++) mythreads[i].join(); System.out.println("Main thread finished"); Exercise02Runnables.java Thread Thread-3 produced value 17 Thread Thread-0 produced value 9 Thread Thread-9 produced value 6 2
Thread Thread-8 produced value 36 Thread Thread-5 produced value 8 Thread Thread-6 produced value 27 Thread Thread-4 produced value 51 Thread Thread-2 produced value 59 Thread Thread-7 produced value 92 Thread Thread-1 produced value 73 Main thread finished Άσκηση 2 Υλοποίηση με synchronized public class Exercise02Synchronized { static Object lock = new Object(); static long SUM = 0; static long X; static int NUMBER_OF_THREADS; public static void main(string[] args) { if (args.length == 0) { X = 10_000_000; NUMBER_OF_THREADS = 4; else { X = Long.parseLong(args[0]); NUMBER_OF_THREADS = Integer.parseInt(args[1]); Thread threads[] = new Thread[NUMBER_OF_THREADS]; for (int tid = 0; tid < threads.length; tid++) { threads[tid] = new TotalizatorThread(tid); threads[tid].start(); for (int tid = 0; tid < threads.length; tid++) { try { threads[tid].join(); catch (InterruptedException e) { System.out.println("Total sum is " + SUM); static class TotalizatorThread extends Thread { int tid; public TotalizatorThread(int id) { tid = id; long mysum = 0; long stride = X / NUMBER_OF_THREADS; long left = tid * stride + 1; long right = tid * stride + stride; if (right > X) right = X; for (long i = left; i <= right; i++) { mysum += i; synchronized (lock) { SUM += i; 3
System.out.printf("Sum computed by thread %d is %d\n", tid, mysum); Exercise02Synchronized.java Sum computed by thread 3 is 21875001250000 Sum computed by thread 1 is 9375001250000 Sum computed by thread 0 is 3125001250000 Sum computed by thread 2 is 15625001250000 Total sum is 50000005000000 Υλοποίηση με ReentrantLock, ThreadPool, Callables και Futures import java.util.concurrent.callable; import java.util.concurrent.executionexception; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.future; import java.util.concurrent.locks.lock; import java.util.concurrent.locks.reentrantlock; public class Exercise02Futures { static Lock lock = new ReentrantLock(); static long SUM = 0; static long X; static int NUMBER_OF_THREADS; public static void main(string[] args) { if (args.length == 0) { X = 10_000_000; NUMBER_OF_THREADS = 4; else { X = Long.parseLong(args[0]); NUMBER_OF_THREADS = Integer.parseInt(args[1]); ExecutorService executor = Executors.newFixedThreadPool(NUMBER_OF_THREADS); Future<Long> futures[] = new Future[NUMBER_OF_THREADS]; for (int tid = 0; tid < futures.length; tid++) futures[tid] = executor.submit(new Totalizator(tid)); executor.shutdown(); for (int tid = 0; tid < futures.length; tid++) { try { lock.lock(); SUM += futures[tid].get(); lock.unlock(); catch (InterruptedException ExecutionException e) { System.out.println("Total sum is " + SUM); static class Totalizator implements Callable<Long> { 4
int tid; public Totalizator(int id) { tid = id; public Long call() { long mysum = 0L; long stride = X / NUMBER_OF_THREADS; long left = tid * stride + 1; long right = tid * stride + stride; if (right > X) right = X; for (long i = left; i <= right; i++) { mysum += i; System.out.printf("Sum computed by thread %d is %d\n", tid, mysum); return mysum; Exercise02Futures.java Άσκηση 3 import java.util.random; import java.util.concurrent.callable; import java.util.concurrent.executionexception; import java.util.concurrent.executorservice; import java.util.concurrent.executors; import java.util.concurrent.future; import java.util.concurrent.locks.reentrantlock; public class Exercise03 { static final int T = 4; static final int N = 1000; static int a[]; static int b[]; public static void main(string[] args) throws InterruptedException, ExecutionException { ReentrantLock lock = new ReentrantLock(); int sum = 0; Random rnd = new Random(); a = new int[n]; b = new int[n]; for (int i = 0; i < N; i++) { a[i] = rnd.nextint(10) + 1; b[i] = rnd.nextint(10) + 1; ExecutorService executor = Executors.newCachedThreadPool(); Future<Integer> futures[] = new Future[T]; for (int i = 0; i < T; i++) futures[i] = executor.submit(new Work(i)); executor.shutdown(); for (int i = 0; i < T; i++) { Integer x = futures[i].get(); 5
lock.lock(); sum += x; lock.unlock(); System.out.println("dot product " + sum); static class Work implements Callable<Integer> { int tid; Exercise03.java public Work(int id) { tid = id; public Integer call() throws Exception { int q = 0; for (int i = tid * N / T; i < (tid + 1) * N / T; i++) q += a[i] * b[i]; return q; Άσκηση 4 import java.util.concurrent.blockingqueue; import java.util.concurrent.threadlocalrandom; public class Producer implements Runnable { BlockingQueue<Integer> buffer; int items; public Producer(BlockingQueue<Integer> buffer, int items) { this.buffer = buffer; this.items = items; for (int i = 0; i < items; i++) { int r = ThreadLocalRandom.current().nextInt(1, 101); try { Thread.sleep(ThreadLocalRandom.current().nextInt(500)); buffer.put(r); System.out.printf("PRODUCER-->produced %d buffer: %s\n", r, buffer); catch (InterruptedException e) { Producer.java import java.util.concurrent.blockingqueue; import java.util.concurrent.threadlocalrandom; 6
public class Consumer implements Runnable { BlockingQueue<Integer> buffer; int items; int sum; public Consumer(BlockingQueue<Integer> buffer, int items) { this.buffer = buffer; this.items = items; sum = 0; int c = 0; while (c < items) { try { Thread.sleep(ThreadLocalRandom.current().nextInt(2000)); int x = buffer.take(); sum += x; c++; System.out.printf("CONSUMER<--consumed %d buffer: %s\n", x, buffer); catch (InterruptedException e) { System.out.println("Total sum " + sum); Consumer.java import java.util.concurrent.arrayblockingqueue; import java.util.concurrent.blockingqueue; public class Exercise04 { public static void main(string[] args) { BlockingQueue<Integer> buffer = new ArrayBlockingQueue<Integer>(10); Thread pt = new Thread(new Producer(buffer, 20)); Thread ct = new Thread(new Consumer(buffer, 20)); pt.start(); ct.start(); Exercise04.java PRODUCER-->produced 40 buffer: [40] PRODUCER-->produced 88 buffer: [40, 88] PRODUCER-->produced 19 buffer: [40, 88, 19] PRODUCER-->produced 40 buffer: [40, 88, 19, 40] PRODUCER-->produced 11 buffer: [40, 88, 19, 40, 11] CONSUMER<--consumed 40 buffer: [88, 19, 40, 11] PRODUCER-->produced 39 buffer: [88, 19, 40, 11, 39] PRODUCER-->produced 15 buffer: [88, 19, 40, 11, 39, 15] PRODUCER-->produced 83 buffer: [88, 19, 40, 11, 39, 15, 83] PRODUCER-->produced 74 buffer: [88, 19, 40, 11, 39, 15, 83, 74] PRODUCER-->produced 78 buffer: [88, 19, 40, 11, 39, 15, 83, 74, 78] PRODUCER-->produced 56 buffer: [88, 19, 40, 11, 39, 15, 83, 74, 78, 56] 7
CONSUMER<--consumed 88 buffer: [19, 40, 11, 39, 15, 83, 74, 78, 56, 91] PRODUCER-->produced 91 buffer: [19, 40, 11, 39, 15, 83, 74, 78, 56, 91] CONSUMER<--consumed 19 buffer: [40, 11, 39, 15, 83, 74, 78, 56, 91, 32] PRODUCER-->produced 32 buffer: [40, 11, 39, 15, 83, 74, 78, 56, 91, 32] CONSUMER<--consumed 40 buffer: [11, 39, 15, 83, 74, 78, 56, 91, 32, 98] PRODUCER-->produced 98 buffer: [11, 39, 15, 83, 74, 78, 56, 91, 32, 98] CONSUMER<--consumed 11 buffer: [39, 15, 83, 74, 78, 56, 91, 32, 98, 99] PRODUCER-->produced 99 buffer: [39, 15, 83, 74, 78, 56, 91, 32, 98, 99] CONSUMER<--consumed 39 buffer: [15, 83, 74, 78, 56, 91, 32, 98, 99, 5] PRODUCER-->produced 5 buffer: [15, 83, 74, 78, 56, 91, 32, 98, 99, 5] CONSUMER<--consumed 15 buffer: [83, 74, 78, 56, 91, 32, 98, 99, 5, 55] PRODUCER-->produced 55 buffer: [83, 74, 78, 56, 91, 32, 98, 99, 5, 55] CONSUMER<--consumed 83 buffer: [74, 78, 56, 91, 32, 98, 99, 5, 55, 38] PRODUCER-->produced 38 buffer: [74, 78, 56, 91, 32, 98, 99, 5, 55, 38] CONSUMER<--consumed 74 buffer: [78, 56, 91, 32, 98, 99, 5, 55, 38, 63] PRODUCER-->produced 63 buffer: [78, 56, 91, 32, 98, 99, 5, 55, 38, 63] CONSUMER<--consumed 78 buffer: [56, 91, 32, 98, 99, 5, 55, 38, 63, 38] PRODUCER-->produced 38 buffer: [56, 91, 32, 98, 99, 5, 55, 38, 63, 38] CONSUMER<--consumed 56 buffer: [91, 32, 98, 99, 5, 55, 38, 63, 38] CONSUMER<--consumed 91 buffer: [32, 98, 99, 5, 55, 38, 63, 38] CONSUMER<--consumed 32 buffer: [98, 99, 5, 55, 38, 63, 38] CONSUMER<--consumed 98 buffer: [99, 5, 55, 38, 63, 38] CONSUMER<--consumed 99 buffer: [5, 55, 38, 63, 38] CONSUMER<--consumed 5 buffer: [55, 38, 63, 38] CONSUMER<--consumed 55 buffer: [38, 63, 38] CONSUMER<--consumed 38 buffer: [63, 38] CONSUMER<--consumed 63 buffer: [38] CONSUMER<--consumed 38 buffer: [] Total sum 1062 Άσκηση 5 import java.awt.gridbagconstraints; import java.awt.gridbaglayout; import java.awt.event.actionevent; import java.awt.event.actionlistener; import java.util.list; import java.util.concurrent.executionexception; import javax.swing.jbutton; import javax.swing.jframe; import javax.swing.jlabel; import javax.swing.swingworker; public class MyFrame extends JFrame { private JLabel mylabel = new JLabel("10"); private JButton mybutton = new JButton("Countdown"); public MyFrame(String title) { super(title); setlayout(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.fill = GridBagConstraints.NONE; gc.gridx = 0; gc.gridy = 0; add(mylabel, gc); gc.gridx = 0; gc.gridy = 2; 8
add(mybutton, gc); mybutton.addactionlistener(new ActionListener() { public void actionperformed(actionevent arg0) { countdown(); ); setsize(200, 200); setdefaultcloseoperation(exit_on_close); setlocationrelativeto(null); setvisible(true); public void countdown() { SwingWorker<Integer, Integer> worker = new SwingWorker<Integer, Integer>() { protected Integer doinbackground() throws Exception { for (int i = 10; i > 0; i--) { Thread.sleep(1000); System.out.println(i); publish(i); return -1; ; worker.execute(); MyFrame.java import javax.swing.swingutilities; protected void process(list<integer> chunks) { Integer value = chunks.get(chunks.size() - 1); mylabel.settext(string.valueof(value)); protected void done() { try { Integer status = get(); System.out.println("Status " + status); mylabel.settext("boom!!!"); catch (InterruptedException e) { // TODO Auto-generated catch block catch (ExecutionException e) { // TODO Auto-generated catch block public class Exercise05 { public static void main(string[] args) { SwingUtilities.invokeLater(new Runnable() { 9
); Exercise05.java new MyFrame("SwingWorker"); 10