principles of software construction: objects, …2019/11/05 · 17-214 2 administrivia • homework...
TRANSCRIPT
1 17-214
PrinciplesofSoftwareConstruction: Objects,Design,andConcurrencyPart3:ConcurrencyIntroductiontoconcurrency:ConcurrencychallengesCharlieGarrodChrisTimperley
2 17-214
Administrivia
• Homework5adue9a.m.tomorrow• MidtermexamavailableonGradescope
– RegraderequestsdueMonday,18November
• Readingduetoday:– JavaConcurrencyinPractice,Sections11.3and11.4
3 17-214
Winteriscomingdiscussion
4 17-214
KeyconceptsfromlastTuesday
5 17-214
Aconcurrencybugwithaneasyfix:
publicclassBankAccount{privatelongbalance;publicBankAccount(longbalance){this.balance=balance;}staticsynchronizedvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){source.balance-=amount;dest.balance+=amount;}publicsynchronizedlongbalance(){returnbalance;}}
6 17-214
ConcurrencycontrolwithJava'sintrinsiclocks
• synchronized(lock){…}– Synchronizesentireblockonobjectlock;cannotforgettounlock– Intrinsiclocksareexclusive:Onethreadatatimeholdsthelock– Intrinsiclocksarereentrant:Athreadcanrepeatedlygetsamelock
• synchronizedonaninstancemethod– Equivalenttosynchronized(this){…}forentiremethod
• synchronizedonastaticmethodinclassFoo– Equivalenttosynchronized(Foo.class){…}forentiremethod
7 17-214
Atomicity
• Anactionisatomicifitisindivisible– Effectively,ithappensallatonce
• Noeffectsoftheactionarevisibleuntilitiscomplete• Nootheractionshaveaneffectduringtheaction
• InJava,integerincrementisnotatomic
i++;
1. Load data from variable i
2. Increment data by 1
3. Store data to variable i
is actually
8 17-214
Yetanotherexample:cooperativethreadtermination
publicclassStopThread{privatestaticbooleanstopRequested;publicstaticvoidmain(String[]args)throwsException{ThreadbackgroundThread=newThread(()->{while(!stopRequested)/*Dosomething*/;});backgroundThread.start();TimeUnit.SECONDS.sleep(42);stopRequested=true;}}
9 17-214
Whatwentwrong?
• Intheabsenceofsynchronization,thereisnoguaranteeastowhen,ifever,onethreadwillseechangesmadebyanother
• JVMscananddoperformthisoptimization:while(!done)/*dosomething*/;
becomes:if(!done)while(true)/*dosomething*/;
Process
Thread
Copy
Thread
Copy
Memory
10 17-214
Today
• Midtermexam2recap• MorebasicconcurrencyinJava
– Somechallengesofconcurrency
• Concurrencypuzzlers• Stillcomingsoon:
– Higher-levelabstractionsforconcurrency– Programstructureforconcurrency– Frameworksforconcurrentcomputation
11 17-214
Alivenessproblem:poorperformance
publicclassBankAccount{privatelongbalance;publicBankAccount(longbalance){this.balance=balance;}staticsynchronizedvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){source.balance-=amount;dest.balance+=amount;}publicsynchronizedlongbalance(){returnbalance;}}
12 17-214
Alivenessproblem:poorperformance
publicclassBankAccount{privatelongbalance;publicBankAccount(longbalance){this.balance=balance;}staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){synchronized(BankAccount.class){source.balance-=amount;dest.balance+=amount;}}publicsynchronizedlongbalance(){returnbalance;}}
13 17-214
Aproposedfix?:locksplitting
publicclassBankAccount{privatelongbalance;publicBankAccount(longbalance){this.balance=balance;}staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){synchronized(source){synchronized(dest){source.balance-=amount;dest.balance+=amount;}}}…}
14 17-214
Alivenessproblem:deadlock
• Apossibleinterleavingofoperations:– bugsThreadlocksthedaffyaccount– daffyThreadlocksthebugsaccount– bugsThreadwaitstolockthebugsaccount…– daffyThreadwaitstolockthedaffyaccount…
15 17-214
Alivenessproblem:deadlock
publicclassBankAccount{privatelongbalance;publicBankAccount(longbalance){this.balance=balance;}staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){synchronized(source){synchronized(dest){source.balance-=amount;dest.balance+=amount;}}}…}
16 17-214
Avoidingdeadlock
• Thewaits-forgraphrepresentsdependenciesbetweenthreads– Eachnodeinthegraphrepresentsathread– AnedgeT1->T2representsthatthreadT1iswaitingforalockT2owns
• Deadlockhasoccurrediffthewaits-forgraphcontainsacycle• Onewaytoavoiddeadlock:lockingprotocolsthatavoidcycles
ab
c
d
f
e
h
g
i
17 17-214
Avoidingdeadlockbyorderinglockacquisition
publicclassBankAccount{privatelongbalance;privatefinallongid=SerialNumber.generateSerialNumber();
publicBankAccount(longbalance){this.balance=balance;}
staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){BankAccountfirst=source.id<dest.id?source:dest;BankAccountsecond=first==source?dest:source;synchronized(first){synchronized(second){source.balance-=amount;dest.balance+=amount;}}}…
18 17-214
Anothersubtleproblem:Thelockobjectisexposed
publicclassBankAccount{privatelongbalance;privatefinallongid=SerialNumber.generateSerialNumber();
publicBankAccount(longbalance){this.balance=balance;}
staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){BankAccountfirst=source.id<dest.id?source:dest;BankAccountsecond=first==source?dest:source;synchronized(first){synchronized(second){source.balance-=amount;dest.balance+=amount;}}}…
19 17-214
Aneasyfix:Useaprivatelock
publicclassBankAccount{privatelongbalance;privatefinallongid=SerialNumber.generateSerialNumber();privatefinalObjectlock=newObject();publicBankAccount(longbalance){this.balance=balance;}
staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){BankAccountfirst=source.id<dest.id?source:dest;BankAccountsecond=first==source?dest:source;synchronized(first.lock){synchronized(second.lock){source.balance-=amount;dest.balance+=amount;}}}…
20 17-214
Concurrencyandinformationhiding
• Encapsulateanobject'sstate:Easiertoimplementinvariants– Encapsulatesynchronization:Easiertoimplementsynchronizationpolicy
21 17-214
Anaside:JavaConcurrencyinPracticeannotations
@ThreadSafepublicclassBankAccount{@GuardedBy("lock")privatelongbalance;privatefinallongid=SerialNumber.generateSerialNumber();privatefinalObjectlock=newObject();publicBankAccount(longbalance){this.balance=balance;}
staticvoidtransferFrom(BankAccountsource,BankAccountdest,longamount){BankAccountfirst=source.id<dest.id?source:dest;BankAccountsecond=first==source?dest:source;synchronized(first.lock){synchronized(second.lock){source.balance-=amount;dest.balance+=amount;}…
22 17-214
Anaside:JavaConcurrencyinPracticeannotations
• @ThreadSafe• @NotThreadSafe• @GuardedBy• @Immutable
23 17-214
Today
• Midtermexam2recap• MorebasicconcurrencyinJava
– Somechallengesofconcurrency
• Concurrencypuzzlers• Stillcomingsoon:
– Higher-levelabstractionsforconcurrency– Programstructureforconcurrency– Frameworksforconcurrentcomputation
24 17-214
Puzzler:“RacyLittleNumber”
25 17-214
Puzzler:“RacyLittleNumber”
importorg.junit.Test;importstaticorg.junit.Assert.assertEquals;publicclassLittleTest{intnumber;@Testpublicvoidtest()throwsInterruptedException{number=0;Threadt=newThread(()->{assertEquals(2,number);});number=1;t.start();number++;t.join();}}
26 17-214
Howoftendoesthistestpass?
importorg.junit.Test;importstaticorg.junit.Assert.assertEquals;publicclassLittleTest{intnumber;@Testpublicvoidtest()throwsInterruptedException{number=0;Threadt=newThread(()->{assertEquals(2,number);});number=1;t.start();number++;t.join();}}
(a)Italwaysfails(b)Itsometimespasses(c)Italwayspasses(d)Italwayshangs
27 17-214
Howoftendoesthistestpass?
(a)Italwaysfails(b)Itsometimespasses(c)Italwayspasses–butittellsusnothing(d)ItalwayshangsJUnitdoesn’tseeassertionfailuresinotherthreads
28 17-214
Anotherlook
importorg.junit.*;importstaticorg.junit.Assert.*;publicclassLittleTest{intnumber;@Testpublicvoidtest()throwsInterruptedException{number=0;Threadt=newThread(()->{assertEquals(2,number);//JUnitneverseestheexception!});number=1;t.start();number++;t.join();}}
29 17-214
Howdoyoufixit?(1)
//KeeptrackofassertionfailuresduringtestvolatileExceptionexception;volatileErrorerror;//Triggerstestcasefailureifanythreadassertsfailed@AfterpublicvoidtearDown()throwsException{if(error!=null)throwerror;if(exception!=null)throwexception;}
30 17-214
Howdoyoufixit?(2)
Threadt=newThread(()->{try{assertEquals(2,number);}catch(Errore){error=e;}catch(Exceptione){exception=e;}});*YMMV(It’saracecondition)
Nowitsometimespasses*
31 17-214
Themoral
• JUnitdoesnotwell-supportconcurrenttests– Youmightgetafalsesenseofsecurity
• Concurrentclientsbeware…
32 17-214
Puzzler:“PingPong”
publicclassPingPong{publicstaticsynchronizedvoidmain(String[]a){Threadt=newThread(()->pong());t.run();System.out.print("Ping");}privatestaticsynchronizedvoidpong(){System.out.print("Pong");}}
33 17-214
Whatdoesitprint?
publicclassPingPong{publicstaticsynchronizedvoidmain(String[]a){Threadt=newThread(()->pong());t.run();System.out.print("Ping");}privatestaticsynchronizedvoidpong(){System.out.print("Pong");}}
(a)PingPong(b)PongPing(c)Itvaries
34 17-214
Whatdoesitprint?
(a)PingPong(b)PongPing(c)ItvariesNotamultithreadedprogram!
35 17-214
Anotherlook
publicclassPingPong{publicstaticsynchronizedvoidmain(String[]a){Threadt=newThread(()->pong());t.run();//Aneasytypo!System.out.print("Ping");}privatestaticsynchronizedvoidpong(){System.out.print("Pong");}}
36 17-214
Howdoyoufixit?
publicclassPingPong{publicstaticsynchronizedvoidmain(String[]a){Threadt=newThread(()->pong());t.start();System.out.print("Ping");}privatestaticsynchronizedvoidpong(){System.out.print("Pong");}}
NowprintsPingPong
37 17-214
Themoral
• InvokeThread.start,notThread.run• java.lang.ThreadshouldnothaveimplementedRunnable
38 17-214
Summary
• Concurrentprogrammingcanbehardtogetright– Easytointroducebugseveninsimpleexamples
• Comingsoon:– Higher-levelabstractionsforconcurrency– Programstructureforconcurrency– Frameworksforconcurrentcomputation