Atomicity

From CSE231 Wiki
Jump to navigation Jump to search

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

Code To Investigate

Attention niels epting.svg Warning:Although the code below is technically thread-safe, it offers check-then-act usage which leads to atomicity races.
class: CheckThenActCourse.java DEMO: Java.png
methods: isSpaceRemaining
add
drop
package: atomicity.course.studio
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);
		}
	}
}

Code To Implement

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

class: Course.java Java.png
methods: addIfSpace
drop
package: atomicity.course.studio
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.

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: Must be thread safe.

Code To Fix

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;
}

Recalling the song:

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

fix the code to remove the atomicity race.

class: StockPortfolio.java Java.png
methods: transfer
package: atomicity.stockportfolio.studio
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.)

Testing Your Solution

Correctness

class: AtomicityTestSuite.java Junit.png
package: atomicity
source folder: testing/src/test/java