210 likes | 328 Vues
This practical session focuses on the critical concepts of concurrency safety when running multiple threads in parallel. It covers the unpredictability of shared resources, design approaches to avoid safety issues, and strategies like thread confinement, immutability, and synchronization. You'll learn about shared resources, their risks, and solutions such as using locks and immutable objects to maintain data integrity across threads. By examining structured code examples, we’ll illustrate the implications of safe and unsafe practices in concurrent programming. Enhance your understanding of efficient thread management!
E N D
System Programming Practical Session 4: Concurrency / Safety
Safety • Running several threads in parallel is not safe. • Unpredictable results on shared resources. • Design aproaches towards avoiding safety problems • Thread confinement • Immutability • Locking / Synchronization
Shared Resources Shared resource - A resource that is visible to several threads. Objects that may be visisble to several threads - Are not safe. Objectst that cannot be shared (local function variables) - Are safe.
classFoo{ • publicstaticdouble • NUMBER=33.3;} • classClassA{ • publiclongi; • publicVectorv; • publicClassA (){/*…*/} • publicvoiddoSomething( longx,Listlst){ • longlocalVar=0; • Objecto; • o=this.v.elementAt(2); //1 • localVar+=2;//2 • this.i+=2;//3 • x+=2;//4 • lst.elementAt(2);//5 • Foo.NUMBER=4;//6 • localVar=Foo.NUMBER;//7 • } } • classTaskAimplementsRunnable{ • privateClassAa; • privateListlst; • publiclongr; • //… some code …. • publicvoidrun(){ • this.r=2;//8 • this.a.doSomething( • 9,lst);//9 • 8. } • 9. } • 10. classMain{ • 11. publicstaticvoidmain( String[]args){ • 13.ClassAo1=newClassA(); • Threadt1= • newThread(newTaskA(o1)); • 15. t1.start(); • //…some code…. } }
Thread Confinement A resource that is used exclusively by a one single thread is confined to the thread. If all the resources of a method are confined, then it is safe.
publicclassThreadConfinedExample • { • //ThreadConfined • publicCarcreateCar(){ • Enginee=newFuelEngine(); • List<Door>doors=newLinkedList<Door>(); • doors.add(newFrontDoor()); • doors.add(newFrontDoor()); • doors.add(newBackDoor()); • doors.add(newBackDoor()); • Radior=newAMFMRadio(); • Carc=newCar(e,doors,r); • returnc; • } • }
publicclassThreadNotConfinedExample • { • //NotThreadConfined • publicCarcreateCar(Enginee){ • 5.List<Door>doors=newLinkedList<Door>; • 6. doors.add(newFrontDoor()); • 7 doors.add(newFrontDoor()); • 8. doors.add(newBackDoor()); • 9.doors.add(newBackDoor()); • Radior=newAMFMRadio()); • Carc=newCar(e,doors,r); • returnc; • } • }
Immutability An immutable object’s state cannot be changed after construction. • Examples: • String • Integer
Immutability An object is immutable if • All primitive fields are final. • All other fields are references to immutable objects. • The object has been safely published: • Reference to this hasn't escaped during construction. • No thread has accessed the object before the construction completed.
‘this’ escape example Public class ClassA{ ………….. public void setB(ClassB objB) { … } ……… } Public class ClassB{ …………… public ClassB(ClassA objA){ //constructor …………… objA.setB(this); } …………… }
Immutability An object with references to mutable objects can still be immutable! A class will be immutable if all of the following are true: • All of its fields are final • The class is declared final • The this reference is not allowed to escape during construction • Any fields that contain references to mutable objects, such as arrays, collections, or mutable classes: • Are private • Are never returned or otherwise exposed to callers • Are the only reference to the objects that they reference • Do not change the state of the referenced objects after construction
publicfinalclassThreeStooges{ privatefinalSet<String>stooges= newHashSet<String>(); publicThreeStooges(){ stooges.add("Moe"); stooges.add("Larry"); stooges.add("Curly"); } publicbooleanisStooge(Stringname){ returnstooges.contains(name); } }
Synchronization A mechanism allowing safely accessing shared resources. A thread accessing a synchronized method locks the object. The object cannot be accessed by other threads while it is locked.
Synchronization 1. Class Even{ 2. privatelong n = 0; 3. publiclongnext(){ 4. n++; 5. n++; 6.returnn; 7. } 8. }
Synchronization 1. Class Even{ 2. privatelong n = 0; 3. publicsynchronizedlongnext(){ 4. n++; 5. n++; 6.returnn; 7. } 8. }
Synchronizing a block • publicintfoo(){ • //dosomething safe • synchronized(this){ • //do something • return9; • } • }
Solution to safety problem Printer Example (from practical session 1) • classPrinter{ • Printer(){} • /** • *@paramilinenumber • *@paramsthestringtoconcatenate 40 times • */ • publicsynchronizedvoidprintALine(inti,Strings){ • System.out.print(i+")"); • for(intj=0;j<40;j++){ • System.out.print(s); • } • System.out.println(); • } • }
publicclassGoodSynchronization{ • publicstaticvoidmain(String[]a){ • Printerp=newPrinter(); • Threadt1=newThread(newSimpleAsynchronousTask("a",p)); • Threadt2=newThread(newSimpleAsynchronousTask("b",p)); • t1.start();//printssomelinesofaaaa • t2.start();//printssomelinesofbbbb • } } • classSimpleAsynchronousTaskimplementsRunnable{ • Printerm_p; • Stringm_name; • publicSimpleAsynchronousTask(Stringname,Printerp){ • m_p=p; • m_name=name; • } • publicvoidrun(){ • for(inti=0;i<50;i++){ • m_p.printALine(i,m_name); • } • } }
Wrong solution #1 • publicclassBadSynchronization2 • publicstaticvoidmain(String[]a){ • Printerp1=newPrinter(); • Printerp2=newPrinter(); • Threadt1=newThread(newSimpleAsynchronousTask("a",p1)); • Threadt2=newThread(newSimpleAsynchronousTask("b",p2)); • t1.start();//printssomelinesofaaaa • t2.start();//printssomelinesofbbbb • } • } • classSimpleAsynchronousTaskimplementsRunnable{ • .....thesamelikeGoodSynchronization.java • classPrinter{ • .....thesamelikeGoodSynchronization.java • }
Wrong solution #2 (no printer object) • classBadSynchronization{ • publicstaticvoidmain(String[]a){ • Threadt1=newThread(newSimpleAsynchronousTask("a")); • Threadt2=newThread(newSimpleAsynchronousTask("b")); • t1.start();//printssomelinesofaaaa • t2.start();//printssomelinesofbbbb • } • } • classSimpleAsynchronousTaskimplementsRunnable{ • .....thesamelikeGoodSynchronization.java • publicsynchronizedvoidprintALine(inti,Strings){ • System.out.print(i+")"); • for(intj=0;j<40;j++)System.out.print(s); • System.out.println(); • } • }
Summary • The most useful policies for using and sharing objects in a concurrent program are: • Thread-confined • Shared read-only • Shared thread-safe