Java visibility and synchronization - Thinking in Java example - java

I read now Thinking in Java, chapter about atomicity and visibility. There is an example I don't understand.
public class SerialNumberGenerator {
private static volatile int serialNumber = 0;
public static int nextSerialNumber() {
return serialNumber++;
}
}
class CircularSet {
private int[] array;
private int len;
private int index = 0;
public CircularSet(int size) {
array = new int[size];
len = size;
for (int i = 0; i < size; i++) {
array[i] = -1;
}
}
synchronized void add(int i) {
array[index] = i;
index = ++index % len;
}
synchronized boolean contains(int val) {
for (int i = 0; i < len; i++) {
if (array[i] == val)
return true;
}
return false;
}
}
public class SerialNumberChecker {
private static final int SIZE = 10;
private static CircularSet serials = new CircularSet(1000);
private static ExecutorService exec = Executors.newCachedThreadPool();
static class SerialChecker implements Runnable {
#Override
public void run() {
while (true) {
int serial = SerialNumberGenerator.nextSerialNumber();
if (serials.contains(serial)) {
System.out.println("Duplicate: " + serial);
System.exit(0);
}
serials.add(serial);
}
}
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < SIZE; i++) {
exec.execute(new SerialChecker());
}
}
}
example output:
Duplicate: 228
I don't understand how is it possible. Even method nextSerialNumber() is not synchronized and all thread generate different values each thread has own value of serial and each are different. So how is it possible to find duplicate. I cannot imagine of threads execution.

This example shows the post-increment operator is not atomic and not thread-safe.
What happens in this code is:
many (up to 100) threads are started, each executing the same code
in an infinite loop:
an unsynchronized method nextSerialNumber is called, which returns the result of the post-increment operator called on a static variable
a synchronized method contains is called, which checks if the returned value exists in the underlying collection
if yes, the program is terminated
if not, the value is added to the underlying collection
If the post-increment operation was thread-safe then the program would never print "Duplicate" and would never terminate,
since every thread would be getting a different serial number value. This is not the case as two threads
might get exactly the same serial number value.

Related

Is array in java is threadsafe in case : one thread change value, one thread read value?

I write a simple ringbuffer and in method test1() I use one thread is poll() and
one thread is offer(). I test many time but it is always true. Can you explain for me?
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
#SuppressWarnings("unchecked")
public class RingBuffer<T> {
private T[] buffer;
// private volatile T[] buffer;
private int readIndex;
private int writeIndex;
private final int capacity;
private AtomicInteger size;
public RingBuffer(int k) {
this.buffer = (T[]) new Object[k];
this.capacity = k;
this.readIndex = 0;
this.writeIndex = 0;
this.size = new AtomicInteger(0);
}
public boolean offer(T value) {
if (isFull()) return false;
buffer[writeIndex] = value;
writeIndex++;
if (writeIndex == capacity) writeIndex -= capacity;
size.getAndIncrement();
return true;
}
public T poll() {
if (isEmpty()) return null;
int index = readIndex;
T x = buffer[index];
readIndex++;
if (readIndex == capacity) readIndex -= capacity;
size.getAndDecrement();
return x;
}
public boolean isEmpty() {
return size.get() == 0;
}
public boolean isFull() {
return size.get() == capacity;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
test1();
}
}
As you see in the test1() method I use different Thread but the check is true.
Sorry because stackoverflow warning me this question is mostly code so I will paste test1() method in here.
public static void test1() throws ExecutionException, InterruptedException {
RingBuffer<String> buffer = new RingBuffer<>(1000);
AtomicBoolean writeDone1 = new AtomicBoolean(false);
ExecutorService service = Executors.newFixedThreadPool(2);
ExecutorService service1 = Executors.newFixedThreadPool(2);
Callable<List<String>> cw1 = () -> {
List<String > x = new ArrayList<>();
int count = 0;
for (int i = 0; i < 10000000; i++) {
if (buffer.offer( i+"")) {
count++;
x.add(i+"");
}
}
writeDone1.set(true);
System.out.println("num write " + count);
return x;
};
Callable<List<String>> cr = () -> {
List<String> x = new ArrayList<>();
int count = 0;
while (!writeDone1.get()) {
String data = buffer.poll();
if (data != null) {
x.add(data);
count++;
}
}
while (true) {
String data = buffer.poll();
if (data != null) {
x.add(data);
count++;
} else {
break;
}
}
System.out.println("num read " + count);
return x;
};
Future<List<String >> fw = service.submit(cw1);
Future<List<String>> fr = service1.submit(cr);
List<String> sw = fw.get();
List<String> sr = fr.get();
System.out.println(sw.size());
System.out.println(sr.size());
boolean check = true;
for (int i =0 ; i< sw.size() ; i++){
if (!sw.get(i).equals( sr.get(i))){
check = false;
break;
}
}
System.out.println(check);
service.shutdown();
service1.shutdown();
}
If I use only one consumer and producer. I can't write a test make the race conditions here. Can you help me?
Thankyou
If there are one consumer and one producer, then this RingBuffer is thread-safe.
Happens-before is provided by AtomicInteger size: it is read at the start and is written at the end of both poll() and offer().
For example, let's look at poll().
Notice that:
in poll() we read buffer[index] only if we've read size.get()!=0
size.get()!=0 can only happen after size.getAndIncrement() in offer()
size is AtomicInteger, which means it provides happens-before and makes all modifications in offer() visible in poll()
In other words:
buffer[writeIndex]=value in offer()
-(happens-before)-> size.getAndIncrement() in offer()
-(happens-before)-> size.get()!=0 in poll()
-(happens-before)-> T x = buffer[index] in poll()
There is no happens before edge between a write to an array at some position and a read from the same position. So if you don't have any ordering guarantee in place, your code is suffering from a data race.
If you also allow for concurrent offers and concurrent polls, then you also have race conditions on your hands.
It has been quite some time I played with ringbuffers. But normally you make use of a tail and head sequence (e.g. a long). If you make the ringbuffer a power of 2, you can do a cheap mod on the conversion of the sequences to indices. And the head and tail sequence could be relatively expensive volatiles (I really would start with that) and later on you could play with relaxed memory order modes. The head and tail will give you the appropriate happens before edges so don't need to do anything special to the array. With this approach you can also get rid of the 'size'; you can calculate the size as the difference between tail and thehead; the problem with size is that it will cause contention between a thread read/writing to the ringbuffer. Also you need to properly pad the the head/tail fields to prevent false sharing.

Synchronize access to particular indexes in int array

I use the int array.
I use that method to fill indexes in array.
public void makeSelectionOfGivenNumber(int number) throws InterruptedException
{
if (this.table[number]!= 0)
{
int multiple;
multiple = number + number;
while (multiple <= upperRange)
{
this.table[multiple] = 0;
multiple += number;
}
}
}
For example, one thread starts from 2 and eliminates all multiples, a second thread starts from 5 and makes the same activities. In some case the simultaneously the value in index 10 (in both cases are multiples). How to use in this case semaphores or other tools to lock that only one thread has access on particular index, not the whole array. I want that these two threads would work in parallel on the same table.
I think You need to create an additional array of locks (ReadWriteLock, a dimension of the array is how you want) and before each attempt to read/change in the target array to take a lock on reading or on writing the element into the array. To take the lock need to calculate an index from the required index of target array and the capacity of the additional array.
Maybe I'm not quite correctly understood the task
public class SomeTask {
private final ReadWriteLock[] locks = locks(5);
private int[] table;
private int upperRange;
public SomeTask(int[] table, int upperRange) {
this.table = table;
this.upperRange = upperRange;
}
public void makeSelectionOfGivenNumber(int number) {
if (this.table[number] != 0) {
int multiple;
multiple = number + number;
while (multiple <= upperRange) {
ReadWriteLock lock = getLock(multiple);
try {
lock.writeLock().lock();
this.table[multiple] = 0;
} finally {
lock.writeLock().unlock();
}
multiple += number;
}
}
}
private ReadWriteLock getLock(int number) {
return locks[(locks.length - 1) & number];
}
private ReadWriteLock[] locks(int size) {
ReadWriteLock[] result = new ReadWriteLock[size];
for (int i = 0; i < size; i++) {
result[i] = new ReentrantReadWriteLock();
}
return result;
}

Java threading issue?

I am wondering why the result is not 400 000. There are two threads why does it gets blocked?
class IntCell {
private int n = 0;
public int getN() {return n;}
public void setN(int n) {this.n = n;}
}
class Count extends Thread {
private static IntCell n = new IntCell();
#Override public void run() {
int temp;
for (int i = 0; i < 200000; i++) {
temp = n.getN();
n.setN(temp + 1);
}
}
public static void main(String[] args) {
Count p = new Count();
Count q = new Count();
p.start();
q.start();
try { p.join(); q.join(); }
catch (InterruptedException e) { }
System.out.println("The value of n is " + n.getN());
}
}
Why there is so problem with that?
Because the way you increment your variable is not an atomic operation indeed to increment it you:
Get the previous value
Add one to this value
Set a new value
They are 3 operations not done atomically you should either us a synchronized block or use an AtomicInteger instead.
With a synchronized block it would be something like:
synchronized (n) {
temp = n.getN();
n.setN(temp + 1);
}
With an AtomicInteger you will need to rewrite your code as next:
class IntCell {
private final AtomicInteger n = new AtomicInteger();
public int getN() {return n.get();}
public void incrementN(int n) {this.n.addAndGet(n);}
}
for (int i = 0; i < 200000; i++) {
n.incrementN(1);
}
The approach with an AtomicInteger is non blocking so it will be faster
When two threads access one object at the same time, they interfere with each other, and the result is not deterministic. For example, imagine that p reads the value of n and gets, say, 0, then q reads the same value and gets 0 too, then p sets value to 1 and q also sets it to 1 (because it still thinks that it has value 0). Now the value of n is increased by 1, even though both counters "incremented" it once. You need to use synchronized block to make sure the counters won't interfere with each other. See https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html for more.
The problem here is that you allow for race conditions. Consider the block inside the loop:
temp = n.getN();
n.setN(temp + 1);
The code context switch between the time you get the current N and by the time you increment it, making you set an "old" value. One way around this is to ensure the inner part of the loop runs in a synchronized block:
for (int i = 0; i < 200000; i++) {
synchronized (n) { / Here!
temp = n.getN();
n.setN(temp + 1);
}
}

Strange behaviour of synchronized

class TestSync {
public static void main(String[] args) throws InterruptedException {
Counter counter1 = new Counter();
Counter counter2 = new Counter();
Counter counter3 = new Counter();
Counter counter4 = new Counter();
counter1.start();
counter2.start();
counter3.start();
counter4.start();
counter1.join();
counter2.join();
counter3.join();
counter4.join();
for (int i = 1; i <= 100; i++) {
if (values[i] > 1) {
System.out.println(String.format("%d was visited %d times", i, values[i]));
} else if (values[i] == 0) {
System.out.println(String.format("%d wasn't visited", i));
}
}
}
public static Integer count = 0;
public static int[] values = new int[105];
static {
for (int i = 0; i < 105; i++) {
values[i] = 0;
}
}
public static void incrementCount() {
count++;
}
public static int getCount() {
return count;
}
public static class Counter extends Thread {
#Override
public void run() {
do {
synchronized (count) {
incrementCount();
values[getCount()]++;
}
} while (getCount() < 100);
}
}
}
That is a code from one online course. My task is to make this code visit each element of array only once (only for elements from 1 to 100). So I have added simple synchronized block to run method. In case of using values inside of that statement everything works. But with count it doesn't want to work.
What the difference? Both of this objects are static fields inside of the same class. Also I have tried to make count volatile but it hasn't helped me.
PS: a lot of elements are visited 2 times and some of them even 3 times. In case of using values in synchronized all elements are visited only once!!!
Integer is immutable. The moment you call increment method, You get a new object and reference of count variable gets changed and hence leads to an issue.

Java Thread execution on same data

first of all here is the code, you can just copy an paste
import java.util.ArrayList;
public class RepetionCounter implements Runnable{
private int x;
private int y;
private int[][] matrix;
private int xCounter;
private int yCounter;
private ArrayList<Thread> threadArray;
private int rowIndex;
private boolean[] countCompleted;
public RepetionCounter(int x, int y, int [][]matrix)
{
this.x = x;
this.y = y;
this.matrix = matrix;
this.threadArray = new ArrayList<Thread>(matrix.length);
this.rowIndex = 0;
for(int i = 0; i < matrix.length; i++){
threadArray.add(new Thread(this));
}
countCompleted = new boolean[matrix.length];
}
public void start(){
for (int i = 0; i < threadArray.size(); i++){
threadArray.get(i).start();
this.rowIndex++;
}
}
public void count(int rowIndex)
{
for(int i = 0; i < matrix[rowIndex].length; i++){
if (matrix[rowIndex][i] == x){
this.xCounter++;
} else if (matrix[rowIndex][i] == y){
this.yCounter++;
}
}
}
#Override
public void run() {
count(this.rowIndex);
countCompleted[this.rowIndex] = true;
}
public int getxCounter() {
return xCounter;
}
public void setxCounter(int xCounter) {
this.xCounter = xCounter;
}
public int getyCounter() {
return yCounter;
}
public void setyCounter(int yCounter) {
this.yCounter = yCounter;
}
public boolean[] getCountCompleted() {
return countCompleted;
}
public void setCountCompleted(boolean[] countCompleted) {
this.countCompleted = countCompleted;
}
public static void main(String args[]){
int[][] matrix = {{0,2,1}, {2,3,4}, {3,2,0}};
RepetionCounter rc = new RepetionCounter(0, 2, matrix);
rc.start();
boolean ready = false;
while(!ready){
for(int i = 0; i < matrix.length; i++){
if (rc.getCountCompleted()[i]){
ready = true;
} else {
ready = false;
}
}
}
if (rc.getxCounter() > rc.getyCounter()){
System.out.println("Thre are more x than y");
} else {System.out.println("There are:"+rc.getxCounter()+" x and:"+rc.getyCounter()+" y");
}
}
}
What I want this code to do: I give to the object a matrix and tow numbers, and I want to know how much times these two numbers occurs in the matrix. I create as many thread as the number of rows of the matrix (that' why there is that ArrayList), so in this object I have k threads (supposing k is the number of rows), each of them count the occurrences of the two numbers.
The problem is: if I run it for the first time everything work, but if I try to execute it another time I get and IndexOutOfBoundException, or a bad count of the occurrences, the odd thing is that if I get the error, and modify the code, after that it will works again just for once.
Can you explain to me why is this happening?
You are using the same instance of RepetitionCounter for each thread:
for(int i = 0; i < matrix.length; i++){
threadArray.add(new Thread(this));
}
so they will all share the same rowIndex. The code is pretty confusing as it is, so I suggest you encapsulate the logic for the threads in a separate Runnable class with individual row ids:
class ThreadTask implements Runnable {
private int rowId;
private int[][] matrix;
public ThreadTask(int[][] matrix, int rowId) {
this.matrix = matrix; // only a reference is passed here so no worries
this.rowId = rowId;
}
public void run() {
// search on my row
}
}
then:
for(int i = 0; i < matrix.length; i++) {
threadArray.add(new Thread(new ThreadTask(matrix, i)));
}
You need to give each thread its own Runnable. Having them all share the same Runnable is going to cause disastrous race conditions. Separate out the logic each thread needs to do into a Runnable. Then move the part of the code that starts up the threads to a place outside the Runnable.
BTW look into Executors in the java.util.concurrent package, you don't have to use raw threads for this stuff. Also using Executors may give you a better idea about separating what goes into the Task from other stuff.

Categories

Resources