נושאים מתקדמים ב threads

21
ההההה ההההה הההההה הההההה ההההההה הההההההExecutor ThreadPools הההה הההההה ההההההההה ההההה89-210 - םםםםם םםםםם םםםםם6 םםםםםם םםםםםםם ם םםםםםם םםםםםםם םThreads Threads ההההה הההה'ה םםםםם םםםםם םםםםם םםםםם89-210 89-210 ההההה הההה6 ההה"ה2010-2011

Upload: nishan

Post on 20-Jan-2016

75 views

Category:

Documents


2 download

DESCRIPTION

נושאים מתקדמים ב Threads. תכנות מתקדם 89-210 תרגול מספר 6 תשע"א 2010-2011. אליהו חלסצ'י. בשיעור הקודם למדנו על אופן פעולת ה thrads ב java , ואיך להריץ אותם ברמה בסיסית - PowerPoint PPT Presentation

TRANSCRIPT

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

נושאים מתקדמים ב נושאים מתקדמים ב ThreadsThreadsאליהו חלסצ'י

89-21089-210תכנות מתקדם תכנות מתקדם 6תרגול מספר

2010-2011תשע"א

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

הקדמה ב thradsבשיעור הקודם למדנו על אופן פעולת ה •

javaואיך להריץ אותם ברמה בסיסית ,השיטות בהן השתמשנו מתאימות למשימות פשוטות, •

Higher-Levelאך למשימות מורכבות יותר נדרש API כזה שיסתיר לנו את הלוגיקה מאחורי ניהול ה ,

threadsויוכל לבצע משימות מתקדמות יותר ,הוא נחוץ אף יותר עבור אפליקציות כבדות שמנצלות •

באופן מלא את המערכות מרובות המעבדים \ ליבות המצויות כיום

עליו נלמד היוםjava.util.concurrent, נכנס 5בגרסא •

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

תזמון משימותpublic class ThreadTest {

private static class Ping implements Runnable{

public void run(){while(true)System.out.println("ping");}

}

private static class Pong implements Runnable{

public void run(){while(true)System.out.println("pong");}

}

public static void main(String[] args) {

Ping ping=new Ping();

Pong pong=new Pong();

Thread t=new Thread(ping,"thread 1");

Thread t1=new Thread(pong,"thread 2");

t.start();

t1.start();

}

}

מחלקה אחת תמיד כותבתping והשנייה תמיד pong

pingאנו רוצים להתחיל מ ושהשניים יתחלפו בכל חצי

שנייה.

כרגע הם נכתבים לא לפיהסדר ולא לא לפי הקצב

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

public class Player implements Runnable{

private String hit;// ping or pong

Object lock;

public Player(String hit,Object o) {

this.hit=hit;

lock=o;

}

@Override

public void run() {

synchronized (lock) {

while(true){

System.out.println(hit);

lock.notify();

try {

lock.wait();

}catch (InterruptedException e) {}

}}}}

Object obj=new Object();

Thread t1=new Thread(new Player("ping",obj));

Thread t2=new Thread(new Player("pong",obj));

t1.start();

t2.start();

Causer Output t1 t2

t1 ping wait notifyt2 pong notify waitt1 ping wait notifyt2 pong notify waitt1 ping wait notify…

תזמון משימות)(waitדוגמא עם

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

תזמון משימותpublic class ThreadTest {

private static class Ping implements Runnable{

public void run(){

while(true){

System.out.println("ping");

try {Thread.sleep(1000);}

catch (InterruptedException e) {}

}

}

}

private static class Pong implements Runnable{

public void run(){

while(true){

System.out.println("pong");

try {Thread.sleep(1000);}

catch (InterruptedException e) {}

}

}

}

public static void main(String[] args) throws InterruptedException {

Ping ping=new Ping();

Pong pong=new Pong();

Thread t=new Thread(ping,"thread 1");

Thread t1=new Thread(pong,"thread 2");

t.start();

long time2,time=System.currentTimeMillis();

while((time2=System.currentTimeMillis())-time<500);

t1.start();

}

}

ניתן גם לפתור את הבעיה למשךsleepבאמצעות

שנייה, ולהתחיל את הThreadsבהפרש של

חצי שנייה

הפיתרון כמובן מסורבל

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

תזמון משימותimport java.util.Timer;

import java.util.TimerTask;

public class ThreadTest {

private static class Ping extends TimerTask{

public void run(){System.out.println("ping");}

}

private static class Pong extends TimerTask{

public void run(){System.out.println("pong");}

}

public static void main(String[] args){

Ping ping=new Ping();

Pong pong=new Pong();

Timer t=new Timer();

t.scheduleAtFixedRate(ping, 0, 1000);

t.scheduleAtFixedRate(pong, 500, 1000);

}

}

יכולה לבצע את כלTimerהמחלקה ההתאמות הדרושות מאחורי הקלעים

שרץ ברקעthreadולתזמן משימות ב

ניתן לבטל משימות ע"י קריאה לcancel)( אך ה timerימשיך לרוץ

עצמו ע"יtimerניתן לבטל את ה שלו)(cancelקריאה ל

int i;

while((i=System.in.read())!=13);

ping.cancel(); בוטל ping ממשיך t

pong.cancel(); בוטל pong ממשיך t

t.cancel(); בוטל t

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

דוגמת סנכרון משיעור קודם

public class Count {

private int count;

public void setCount(int x){count=x;}

public int getCount(){return count;}

public synchronizedsynchronized void update(){count++;}

}

public class ThreadTest {

private static class CountAdapter implements Runnable{

Count c;

public CountAdapter(Count c){

this.c=c;

}

public void run(){

for(int i=0;i<100000000;i++)

c.update();

}

}

public static void main(String[] args) {

Count c=new Count();

c.setCount(0);

CountAdapter ca=new CountAdapter(c);

Thread t=new Thread(ca);

Thread t1=new Thread(ca);

long time=System.currentTimeMillis();

t.start();

t1.start();

while(t.isAlive() || t1.isAlive());

System.out.println(c.getCount());

System.out.println((System.currentTimeMillis()-time)/1000);

}}

שיעור קודם שחקנו עם מיקום הסנכרוןוהגענו לפשרה בין מקביליות למהירות

בדוגמא אפשרנו מקביליות על חשבוןמהירות ריצה...

שניות46זמן הריצה היה כ

כעת נשתמש במשתנה אטומי

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

משתנים אטומיים

import java.util.concurrent.atomic.AtomicInteger;

public class Count {

private AtomicInteger count=new AtomicInteger(0);

public void setCount(int x){count.set(x);}

public int getCount(){return count.get();}

public void update(){

count.incrementAndGet();// count++

}

}

public class ThreadTest {

private static class CountAdapter implements Runnable{

Count c;

public CountAdapter(Count c){

this.c=c;

}

public void run(){

for(int i=0;i<100000000;i++)

c.update();

}

}

public static void main(String[] args) {

Count c=new Count();

c.setCount(0);

CountAdapter ca=new CountAdapter(c);

Thread t=new Thread(ca);

Thread t1=new Thread(ca);

long time=System.currentTimeMillis();

t.start();

t1.start();

while(t.isAlive() || t1.isAlive());

System.out.println(c.getCount());

System.out.println((System.currentTimeMillis()-time)/1000);

}}

הפעם השתמשנו באובייקטAtomicInteger רק – thread אחד

יכול לבצע עליו פעולות.

שניות.6זמן הריצה היה כ

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

deadlockדוגמא ל public class Friend {

private String name;

public Friend(String name){this.name = name;}

public String getName(){return this.name;}

public synchronized void sayHA(Friend date) {

System.out.format("%s says HA to %s%n",this.name, date.getName());

date.sayDA(this);

}

public synchronized void sayDA(Friend date) {

System.out.format("%s says DA to %s%n",this.name,date.getName());

}

}

נתון הפרוטוקול הבא לפתיחת "דייט": אם אחד המשתתפים אומר

"הא" האחר צריך להשיב "דה"

threads החיים ב Bob ו Aliceבדוגמא, נפרדים, יצאו ל"דייט"

שניהם מתפרצים ואומרים "הא"• בגלל הסנכרון על אמירת ה"הא", האובייקטים•

נעולים עד שאמירת ה"הא"Bob ושל Alice של תסתיים

אמירת ה"הא" לא מסתיימת עד שהאחר• יאמר "דה"

אבל יש גם סנכרון על אמירת ה"דה", ואם• השני לא יכולThread האובייקט נעול, ה

להיכנס אליו• Alice ו Bobתקועים בשתיקה מביכה

public class DeadLock {

private static class FriendRun implements Runnable{

private Friend me,date;

public FriendRun(Friend m,Friend d){ me=m;date=d;}

public void run(){ me.sayHA(date); }

}

public static void main(String[] args) {

Friend alice = new Friend("Alice");

Friend bob = new Friend("Bob");

Thread t=new Thread(new FriendRun(alice,bob));

Thread t1=new Thread(new FriendRun(bob,alice));

t.start();

t1.start();

}}

Alice says HA to Bob

Bob says HA to Alice

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

deadlockדוגמא ל public class Friend {

private String name;

public Friend(String name){this.name = name;}

public String getName(){return this.name;}

public synchronized void sayHA(Friend date) {

System.out.format("%s says HA to %s%n",this.name, date.getName());

date.sayDA(this);

}

public synchronized void sayDA(Friend date) {

System.out.format("%s says DA to %s%n",this.name,date.getName());

}

}

public class DeadLock {

private static class FriendRun implements Runnable{

private Friend me,date;

public FriendRun(Friend m,Friend d){ me=m;date=d;}

public void run(){ me.sayHA(date); }

}

public static void main(String[] args) {

Friend alice = new Friend("Alice");

Friend bob = new Friend("Bob");

Thread t=new Thread(new FriendRun(alice,bob));

Thread t1=new Thread(new FriendRun(bob,alice));

t.start();

t1.start();

}}

A

B

t2 FR AB

t1 FR A B

A.sayHA)(Aנעול

Start)(

B.sayHA)(Bנעול

Start)(

t1: B.sayDA)( נעולBא"א

לא יוצאים מ A.sayHa)(

A...נשאר נעול

t2: A.sayDA)( נעולAא"א

לא יוצאים מ B.sayHa)(

B...נשאר נעול

HAאף צד לא סיים לומר

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

lockנעילת אובייקטים ע"י import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class Friend {

private String name;

privateprivate Lock Lock locklock = = newnew ReentrantLock(); ReentrantLock();

public Friend(String name){this.name = name;}

public String getName(){return this.name;}

public boolean iCanLockBoth(Friend date) {

Boolean myLock = false;

Boolean yourLock = false;

try {

myLock=lock.tryLock();

yourLock=date.lock.tryLock();

} finally {

if (!(myLock&&yourLock)) {

if (myLock) lock.unlock();

if (yourLock) date.lock.unlock();

}

}

return myLock&&yourLock;

}

iCanLockBoth 2 יחסיר אמת רק אם הצלחנו לנעול את האובייקטים נעולים ע"י2המנעולים )שלי ושל ה "דייט"( כלומר

וכעת אין בעיה שאמירת ה"הא" תצפה ל"דה"threadאותו ה

public void sayHA(Friend date) {

if(iCanLockBoth(date)){

try{

System.out.format("%s says HA to %s%n",this.name,date.getName());

date.sayDA(this);

} finally{

lock.unlock();

date.lock.unlock();

}

} else

System.out.format("%s started to say HA but realized %s already started",name,date.getName());

}

Alice says HA to Bob

Bob says DA to Alice

Bob started to say HA but realized Alice already started

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

Executorהממשק

בדוגמאות שראינו עד עתה היה קשר קרוב בין • threadהמשימה שצריכה להתבצע לבין ה

שמריץ אותה

באפליקציות קטנות זה בסדר, אך באפליקציות •גדולות הגיוני יותר להפריד את יצירת וניהול ה

threadsמשאר האפליקציה

משמש אותנו לכךExecutorממשק ה •

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

Executorהממשק

לממשק יש מתודה אחת בשם:•(public void execute)Runnable r

בידנו)(r.runכאשר השליטה איך להריץ את •

דוגמאות:•הרצה ישירה:–

נפרדthreadהרצה ב –לכל משימה:

class DirectExecutor implements Executor {

public void execute(Runnable r) {

r.run();

}

}

class ThreadPerTaskExecutor implements Executor {

public void execute(Runnable r) {

new Thread(r).start();

}

}

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

Executorהממשק שרצים threadsנניח שאנו נרצה לשלוט בכמות ה •

במקביל, כדי לשלוט בעומס על המערכת. threads מסוים של Nנוכל לממש תור שיאפשר רק ל •

ThreadPoolלרוץ מתוכו. שיטה זו נקראת אופן המימוש:•

לתור.r פשוט נכניס את executeבמתודה – מהתור, ומריצה N Runnables ששולפת runנממש מתודה בשם –

משלהםthreadsאותם ב לא נשלוף אחרים כל עוד אלו לא הסתיימו–

וכו' sleep, waitאבל נצטרך לטפל במקרים שונים של •שזה כבר יותר קשה לממש בצורה טובה

ThreadPools כבר ממשו java.util.concurrentלכן ב •חזקים וגמישים

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

ThreadPoolsimport java.util.concurrent.Executor;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ThreadTest3 {

private static void delay(long ms){

try { Thread.sleep(ms);}

catch (InterruptedException e) {}

}

private static class RunnableTask1 implements Runnable{

public void run(){

System.out.println("task1 started");

delay(10000);

System.out.println("task1 finished");

}

}…

RunnableTask2ובהתאמה המחלקות RunnableTask 3ו

public static void main(String[] args) {

Executor executor = Executors.Executors.newSingleThreadExecutornewSingleThreadExecutor();();

executor.execute (new RunnableTask1 ());

executor.execute (new RunnableTask2 ());

executor.execute (new RunnableTask3 ());

((ExecutorService) executor).shutdown();

}

שיוצרfactoryאנו קוראים בצורה סטטית ל ExectuterServiceכאשר במקרה שלנו ,

newSingleTreadExecutor)(מאפשר רק אחד לרוץ בכל פעם.threadל

task1 startedאיך יראה הפלט?

task1 finished

task2 started

task2 finished

task3 started

task3 finished

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

ThreadPoolsimport java.util.concurrent.Executor;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ThreadTest3 {

private static void delay(long ms){

try { Thread.sleep(ms);}

catch (InterruptedException e) {}

}

private static class RunnableTask1 implements Runnable{

public void run(){

System.out.println("task1 started");

delay(10000);

System.out.println("task1 finished");

}

}…

RunnableTask2ובהתאמה המחלקות RunnableTask 3ו

public static void main(String[] args) {

Executor executor = Executors.Executors.newFixedThreadPoolnewFixedThreadPool (2); (2);

executor.execute (new RunnableTask1 ());

executor.execute (new RunnableTask2 ());

executor.execute (new RunnableTask3 ());

((ExecutorService) executor).shutdown();

}

Executors.newFixedThreadPoolהפעם לרוץ.threadsמאפשר רק למספר מסוים של

איך יראה הפלט?

task1 started

task2 started

task1 finished

task2 finished

task3 started

task3 finished

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

ThreadPoolsimport java.util.concurrent.Executor;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class ThreadTest3 {

private static void delay(long ms){

try { Thread.sleep(ms);}

catch (InterruptedException e) {}

}

private static class RunnableTask1 implements Runnable{

public void run(){

System.out.println("task1 started");

delay(10000);

System.out.println("task1 finished");

}

}…

RunnableTask2ובהתאמה המחלקות RunnableTask 3ו

public static void main(String[] args) {

Executor executor = Executors.Executors.newCachedThreadPoolnewCachedThreadPool();();

executor.execute (new RunnableTask1 ());

executor.execute (new RunnableTask2 ());

executor.execute (new RunnableTask3 ());

((ExecutorService) executor).shutdown();

}

Executors.newCachedThreadPoolל threadsאין הגבלה על מספר ה

איך יראה הפלט?

task1 started

task2 started

task3 started

task1 finished

task3 finished

task2 finished

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

Callable, Futureimport java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

public class ThreadTest3 {

private static void delay(long ms){

try { Thread.sleep(ms);}

catch (InterruptedException e) {}

}

private static class CallableTask implements Callable<Integer>{

Integer i;

public CallableTask(int i){

this.i=new Integer(i);

}

public Integer call() throws Exception {

System.out.printf("task%d started\n",i);

delay(10000);

return i;

}

}

public static void main(String[] args) throws InterruptedException, ExecutionException {

ExecutorService executor = Executors.newCachedThreadPool();

Future<Integer> futures[]=new Future[3];

for(int i=0;i<3;i++)

futures[i]=executor.submit (new CallableTask(i+1));

executor.shutdown();

for(int i=0;i<3;i++)

System.out.printf("task%d finished\n",futures[i].get());

}

ExecutorServiceיודע לעבוד גם עם Callable שבדומה ל ,Runnableגם לו

, אך היא יכולה להחזירcallמתודה אחת כרצוננו, וכךexceptionערך ואף לזרוק

קל יותר להעביר מידע.

תחזיר את הערך שלsubmitהמתודה call לתוך אובייקט מסוג Future.

מתודות שימושיות נוספות.Futureל

task1 started

task2 started

task3 started

task1 finished

task3 finished

task2 finished

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

מבני נתונים מסונכרנים אינם מסונכרניםjava.utilרוב מבני הנתונים של •ניתן לעטוף אותם בטיפוסים מסונכרנים לדוגמא:•כך רק מי שצריך, משלם את•

מחיר זמן הריצה..., רצף של פעולות thread-safeבעוד שפעולות בודדות הן •

thread-safeהתלויות כל אחת בתוצאת קודמתה, אינה לגמרייthread-safeטעות נפוצה היא לחשוב ששיטה זו •java.util.concurrent, נוספו מבני הנתונים ב 5בגרסא • לחלוטין, ואף מהירים thread-safeמבני נתונים אלו הם •

synchronizedבהרבה ממבנה רגיל העטוף ב מבני נתונים:•

–ArrayBlockingQueue<E> –ConcurrentHashMap<K,V> –ConcurrentLinkedQueue<E>

private Map<String,Integer> hm = Collections.synchronizedMap( new HashMap<String,Integer>());

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

הטמעה Bobהאם תמיד מובטח שהמחשב ימליץ ל •

? )הקוד בשקף הבא(Aliceלצאת עם

הראו תוכנית שתבטיח זאת•

בכמה HashMapכתבו תוכנית שמעדכנת •threadsברמה שחוסר הסנכרון יפגע בתוצאות

עטפו את המחלקה בסנכרון, ומדדו את הזמן.•

החליפו את מבנה הנתונים ל •ConcurrentHashMapומדדו את הזמן שוב

הקדמהתזמון משימות

משתנים אטומייםמנעוליםExecutor

ThreadPoolsמבני נתונים מסונכרנים

הטמעה

תכנות מתקדם - תרגול 89-2106

public class ThreadTest4 {

static String message;

private static class CorrectorThread extends Thread {

public void run() {

try {sleep(1000);}

catch (InterruptedException e) {}

message = "Bob, ask Alice on a date.";

}

}

public static void main(String args[]) throws InterruptedException {

(new CorrectorThread()).start();

message = "Bob, don't ask Alice on a date.";

Thread.sleep(2000);

System.out.println(message);

}

}