Difference between revisions of "Atomicity"

From CSE231 Wiki
Jump to navigation Jump to search
Line 21: Line 21:
 
''get then put is not atomic<br>call [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction- compute]<br>call [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction- compute]<br>use [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html ConcurrentHashMap]<br>use [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html ConcurrentHashMap]<br>or say shoot!<br>or say shoot!''
 
''get then put is not atomic<br>call [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction- compute]<br>call [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html#compute-K-java.util.function.BiFunction- compute]<br>use [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html ConcurrentHashMap]<br>use [https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html ConcurrentHashMap]<br>or say shoot!<br>or say shoot!''
  
=Exercise=
+
=SuspectWordCount=
==SuspectWordCount==
 
 
<youtube>glpqcoTELi0</youtube>
 
<youtube>glpqcoTELi0</youtube>
===Code To Fix: countWords===
+
==Code To Fix: countWords==
 
{{Warning|Do NOT use synchronized here.  ConcurrentMaps are already thread safe.}}
 
{{Warning|Do NOT use synchronized here.  ConcurrentMaps are already thread safe.}}
  
Line 30: Line 29:
 
{{CodeToDebug|SuspectWordCount|countWords|atomicity.wordcount.exercise}}
 
{{CodeToDebug|SuspectWordCount|countWords|atomicity.wordcount.exercise}}
 
{{Parallel|public static Map<String, Integer> countWords(Iterable<String> words)}}
 
{{Parallel|public static Map<String, Integer> countWords(Iterable<String> words)}}
==StockPortfolio==
+
=StockPortfolio=
 
<youtube>z9IvYmvyIh0</youtube>
 
<youtube>z9IvYmvyIh0</youtube>
===Code To Fix: transfer===
+
==Code To Fix: transfer==
 
{{Warning|Do NOT use synchronized here.  ConcurrentMaps are already thread safe.}}
 
{{Warning|Do NOT use synchronized here.  ConcurrentMaps are already thread safe.}}
  
Line 59: Line 58:
 
NOTE: do not be concerned about ConcurrentMap vs ConcurrentHashMap.  The supplier's get method will return an instance of a thread-safe map.  (It will, in fact, be an instance of ConcurrentHashMap.)
 
NOTE: do not be concerned about ConcurrentMap vs ConcurrentHashMap.  The supplier's get method will return an instance of a thread-safe map.  (It will, in fact, be an instance of ConcurrentHashMap.)
  
==Course==
+
=CheckThenActCourse and Course=
 
<youtube>gtcOC0RdnMA</youtube>
 
<youtube>gtcOC0RdnMA</youtube>
===Code To Investigate: CheckThenActCourse===
+
==CheckThenActCourse==
 +
===Code To Investigate===
 
{{Warning|Although the class below is technically thread-safe, it offers check-then-act usage which leads clients to atomicity races.}}
 
{{Warning|Although the class below is technically thread-safe, it offers check-then-act usage which leads clients to atomicity races.}}
  
Line 98: Line 98:
 
}</nowiki>
 
}</nowiki>
  
===Code To Investigate: Course drop===
+
 
 +
==Course==
 +
We will build a thread-safe <code>Course</code> class with methods which do not lead clients towards atomicity races.
 +
===Code To Investigate===
 +
====drop====
 
{{ThreadSafe|public boolean drop(Student student)}}
 
{{ThreadSafe|public boolean drop(Student student)}}
  
 
Removes the student from the course if the student was enrolled (the remove method returns just the status you need).
 
Removes the student from the course if the student was enrolled (the remove method returns just the status you need).
  
NOTE: Must be thread safe.
+
NOTE: This method is thread safe.
 
 
===Code To Implement: Course addIfSpace===
 
We will build a thread-safe <code>Course</code> class with methods which do not lead clients towards atomicity races.
 
  
{{CodeToImplement|Course|addIfSpace<br>drop|atomicity.course.exercise}}
+
===Code To Implement===
 +
====addIfSpace====
 +
{{CodeToImplement|Course|addIfSpace|atomicity.course.exercise}}
  
 
{{ThreadSafe|public boolean addIfSpace(Student student)}}
 
{{ThreadSafe|public boolean addIfSpace(Student student)}}

Revision as of 02:48, 1 May 2022

Motivation

Many race conditions can be prevented by proper encapsulation avoiding check-then-write and read-then-modify-then-write in non-atomically.

Background

Take a look at the synchronized and lock sections of the reference page

Concurrency Tutorial

Synchronized Methods
Intrinsic Locks

ConcurrentMap

compute

Lecture

Song to Recall

get then put is not atomic
call compute
call compute
use ConcurrentHashMap
use ConcurrentHashMap
or say shoot!
or say shoot!

SuspectWordCount

Code To Fix: countWords

Attention niels epting.svg Warning:Do NOT use synchronized here. ConcurrentMaps are already thread safe.

fix the code to remove the atomicity race.

class: SuspectWordCount.java Debugging icon.png
methods: countWords
package: atomicity.wordcount.exercise
source folder: student/src/main/java

method: public static Map<String, Integer> countWords(Iterable<String> words) Parallel.svg (parallel implementation required)

StockPortfolio

Code To Fix: transfer

Attention niels epting.svg Warning:Do NOT use synchronized here. ConcurrentMaps are already thread safe.

For this part of the studio we are presented with broken code. Despite using a thread-safe concurrent map:

private final ConcurrentMap<String, Integer> map;

it suffers from an atomicity race:

private int transfer(String listingSymbol, int deltaShareCount) {
	Integer oldValue = this.map.get(listingSymbol);
	Integer newValue;
	if (oldValue != null) {
		newValue = oldValue + deltaShareCount;
	} else {
		newValue = deltaShareCount;
	}
	this.map.put(listingSymbol, newValue);
	return newValue;
}
class: StockPortfolio.java Java.png
methods: transfer
package: atomicity.stockportfolio.exercise
source folder: student/src/main/java

method: private int transfer(String listingSymbol, int deltaShareCount) Sequential.svg (thread-safe required)

NOTE: do not be concerned about ConcurrentMap vs ConcurrentHashMap. The supplier's get method will return an instance of a thread-safe map. (It will, in fact, be an instance of ConcurrentHashMap.)

CheckThenActCourse and Course

CheckThenActCourse

Code To Investigate

Attention niels epting.svg Warning:Although the class below is technically thread-safe, it offers check-then-act usage which leads clients to atomicity races.
class: CheckThenActCourse.java DEMO: Java.png
methods: isSpaceRemaining
add
drop
package: atomicity.course.demo
source folder: src//java
public class CheckThenActCourse {
	private final Collection<Student> students;
	private final int limit;

	public CheckThenActCourse(int limit, Supplier<Collection<Student>> collectionSupplier) {
		this.students = collectionSupplier.get();
		this.limit = limit;
	}

	public int getLimit() {
		return this.limit;
	}

	public boolean isSpaceRemaining() {
		synchronized (this.students) {
			return this.students.size() < this.limit;
		}
	}

	public void add(Student student) {
		synchronized (this.students) {
			this.students.add(student);
		}
	}

	public boolean drop(Student student) {
		synchronized (this.students) {
			return this.students.remove(student);
		}
	}
}


Course

We will build a thread-safe Course class with methods which do not lead clients towards atomicity races.

Code To Investigate

drop

method: public boolean drop(Student student) Sequential.svg (thread-safe required)

Removes the student from the course if the student was enrolled (the remove method returns just the status you need).

NOTE: This method is thread safe.

Code To Implement

addIfSpace

class: Course.java Java.png
methods: addIfSpace
package: atomicity.course.exercise
source folder: student/src/main/java

method: public boolean addIfSpace(Student student) Sequential.svg (thread-safe required)

Adds the student if there is space under the limit specified to the constructor and returns whether or not the add actually occurred.

NOTE: Must be thread safe.

Testing Your Solution

Correctness

class: _AtomicityTestSuite.java Junit.png
package: atomicity
source folder: testing/src/test/java
class: _WordCountAtomicityTestSuite.java Junit.png
package: atomicity.wordcount.exercise
source folder: testing/src/test/java
class: _StockPortfolioAtomicityTestSuite.java Junit.png
package: atomicity.stockportfolio.exercise
source folder: testing/src/test/java
class: _CourseAtomicityTestSuite.java Junit.png
package: atomicity.course.exercise
source folder: testing/src/test/java