I've read a lot about thread-safety. In certain part of my multi-threaded program, I preferred to try the immutability. After getting incorrect results, I noticed my immutable object is not thread-safe although it is 100% immutable. Please correct me if I'm wrong.
public final class ImmutableGaugeV4 {
private final long max, current;
public ImmutableGaugeV4(final long max) {
this(max, 0);
}
private ImmutableGaugeV4(final long max, final long current) {
this.max = max;
this.current = current;
}
public final ImmutableGaugeV4 increase(final long increment) {
final long c = current;
return new ImmutableGaugeV4(max, c + increment);
}
public final long getCurrent() {
return current;
}
public final long getPerc() {
return current * 100 / max;
}
#Override
public final String toString() {
return "ImmutableGaugeV4 [max=" + max + ", current=" + current + "](" + getPerc() + "%)";
}
}
aaaaa
public class T4 {
public static void main(String[] args) {
new T4().x();
}
ImmutableGaugeV4 g3 = new ImmutableGaugeV4(10000);
private void x() {
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
for (int j = 0; j < 1000; j++) {
g3 = g3.increase(1);
System.out.println(g3);
}
}
}.start();
}
}
}
Sometimes I'm getting correct results, and most of the times I'm not
ImmutableGaugeV4 [max=10000, current=9994](99%)
ImmutableGaugeV4 [max=10000, current=9995](99%)
ImmutableGaugeV4 [max=10000, current=9996](99%)
ImmutableGaugeV4 [max=10000, current=9997](99%)
What is wrong with this immutable object? What is missing to make it thread-safe without using intrinsic locks?
Neither
final long c = current;
return new ImmutableGaugeV4(max, c + increment);
nor
g3 = g3.increase(1);
is thread-safe. These compound actions aren't atomic.
I recommend reading "Java concurrency in practice" by Brian Goetz: the chapters devoted to compound actions and "publication and escape" problems.
Your problem is that you are not using thread safe operations for your numeric variables max and current. Because of that, many threads can get the same value from them even tough it has already been changed.
You could add synchronized blocks to handle reading / writing to them, but the best approach is to use thread safe classes to handle that for you.
If you need long values, that would be AtomicLong. Take a look at it’s documentation, it has methods to do the operations you want.
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicLong.html
Whenever you’re multithreading you should go for threadsafe objects, such as the Atomic family, ConcurrentHashMap for maps, and so on.
Hope it helps!
The only problem here is the following line:
g3 = g3.increase(1);
This is equivalent to the following lines:
var tmp = g3;
tmp = tmp.increase(1);
g3 = tmp;
To fix this, you could use a Compare And Swap:
private static final VarHandle G3;
static {
try {
G3 = MethodHandles.lookup().findVarHandle(T4.class, "g3", ImmutableGaugeV4.class);
} catch (ReflectiveOperationException roe) {
throw new Error(roe);
}
}
And then replace g3 = g3.increase(1); with:
ImmutableGaugeV4 oldVal, newVal;
do {
oldVal = g3;
newVal = oldVal.increase(1);
} while (!G3.compareAndSet(T4.this, oldVal, newVal));
System.out.println(newVal);
In the end, your T4 becomes:
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class T4 {
public static void main(String[] args) {
new T4().x();
}
ImmutableGaugeV4 g3 = new ImmutableGaugeV4(10000);
private static final VarHandle G3;
static {
try {
G3 = MethodHandles.lookup().findVarHandle(T4.class, "g3", ImmutableGaugeV4.class);
} catch (ReflectiveOperationException roe) {
throw new Error(roe);
}
}
private void x() {
for (int i = 0; i < 10; i++) {
new Thread() {
public void run() {
for (int j = 0; j < 1000; j++) {
ImmutableGaugeV4 oldVal, newVal;
do {
oldVal = g3;
newVal = oldVal.increase(1);
} while (!G3.compareAndSet(T4.this, oldVal, newVal));
System.out.println(newVal);
}
}
}.start();
}
}
}
Related
The program's aim is to simulate that multiple users add a number to the buffer from 0 to n. Then print the sum of numbers in the buffer. When I run the program, it seems that the threads never end. However, the thread will finish when I run the program in debug mode of Idea and step line by line. Also, I do not exactly know where I need to use my semaphore method P() and V() for mutual exclusion.
Version: JDK 8. I cannot use semaphore in the library.
Main.java
Buffer b = new Buffer(bufferSize);
ArrayList<user> us = new ArrayList<>();
for(int i = 0; i < num_users; i++) us.add(new user(i, elements, b));
ArrayList<Thread> th = new ArrayList<>();
for(int i = 0; i < num_users; i++)
{
th.add(new Thread(us.get(i)));
th.get(i).start();
}
user.java
public class user implements Runnable
{
private int id;
private int num_elements;
private semaphore mutex = new semaphore(1 );
public static Buffer buf;
public user(int i, int el, Buffer b)
{id = i; num_elements = el; buf = b;}
public void add_elements()
{//Add element to buffer, element value iterates from 0, 1, 2 .... num_elements
mutex.P();
int n = 0;
while (num_elements > 0)
{
buf.add(new Integer(n));
n++;
num_elements--;
}
mutex.V();
}
public void run()
{
add_elements();
}
}
Buffer.java
public class Buffer
{
private LinkedList<Object> buf_list;
private int elements; //Number of elements currently on the queue
private int buf_size; //Maximum number of elements allowed on queue
private semaphore mutex = new semaphore(1);
public Buffer(int n) //Queue creation, with n indicating the maximum capacity
{
buf_list = new LinkedList<Object>();
elements = 0;
buf_size = n;
}
public void add(Integer n)
{
mutex.P();
buf_list.add(n);
elements++;
mutex.V();
}
public void finalSummation()
{
if (elements == buf_size)
{
mutex.P();
int sum = 0;
for (Object n : buf_list)
sum += ((Integer)n).intValue();
mutex.V();
System.out.println("Count total: " + sum);
}
}
}
semaphore.java
public class semaphore
{
private int count = 0;
public semaphore(int init_count)
{
count = init_count;
}
public synchronized void P()
{
count -= 1;
while (count < 0)
{
try {
wait();
} catch (InterruptedException e) {
System.out.println("Error");
System.exit(-1);
}
}
}
public synchronized void V()
{
count += 1;
notifyAll();
}
}
I expect it will print the sum of buffer numbers, but the thread may not finish.
There are a few things that stand out as issues here.
1) your code is never calling the finalSummation method. So the "printing" of the result will never happen.
2) Buffer and each user are all creating their own semaphores. If you are attempting to allow multiple threads to update Buffer without colliding then you need to share the same semaphore. Remove the semaphore and the usage of it from the user class. Just let the Buffer instance control only one update at a time with its semaphore.
3) You don't need to check the semaphore in the finalSummation method. Presumably, all threads are done at that point. And to enforce that ...
4) Put code like this at the end of main
for(int i = 0; i < num_users; i++) {
th.get(i).join();
}
b.finalSummation();
5) A semaphore should manage a number of permits. Your semaphore is managing the number of instances waiting - that is a pretty much an irrelevant number for a semaphore. Change your P() and V() to acquire() and release() to be consistent with the pattern.
public static class semaphore {
private int permits = 0;
public semaphore(int permits) {
this.permits = permits;
}
public synchronized void acquire() {
while (permits < 1) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("Error");
System.exit(-1);
}
}
permits--;
}
public void release() {
synchronized (this) {
permits += 1;
notifyAll();
}
}
}
I have put it together using the above answer if that helps. Please select above answer as the right answer.
import java.util.ArrayList;
import java.util.LinkedList;
public class Main {
// assumed values
private static final int bufferSize = 5;
private static final int num_users = 10;
private static final int elements = 5;
public static void main(String[] args) {
Buffer b = new Buffer(bufferSize);
ArrayList<User> us = new ArrayList<>();
for(int i = 0; i < num_users; i++) us.add(new User(i, elements, b));
ArrayList<Thread> th = new ArrayList<>();
for(int i = 0; i < num_users; i++)
{
th.add(new Thread(us.get(i)));
th.get(i).start();
}
for(int i = 0; i < num_users; i++) {
try {
th.get(i).join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
b.finalSummation();
System.out.println("Exiting");
}
}
class User implements Runnable
{
private int id;
private int num_elements;
public static Buffer buf;
public User(int i, int el, Buffer b)
{id = i; num_elements = el; buf = b;}
public void add_elements()
{//Add element to buffer, element value iterates from 0, 1, 2 .... num_elements
int n = 0;
while (num_elements > 0)
{
buf.add(new Integer(n));
n++;
num_elements--;
}
}
public void run()
{
add_elements();
}
}
class Buffer
{
private LinkedList<Object> buf_list;
private int elements; //Number of elements currently on the queue
private int buf_size; //Maximum number of elements allowed on queue
private Semaphore mutex ;
public Buffer(int n) //Queue creation, with n indicating the maximum capacity
{
buf_list = new LinkedList<Object>();
elements = 0;
buf_size = n;
mutex = new Semaphore(buf_size);
}
public synchronized void add(Integer n)
{
mutex.acquire();
buf_list.add(n);
elements++;
mutex.release();
}
public void finalSummation()
{
int sum = 0;
System.out.println(buf_list);
for (Object n : buf_list)
sum += ((Integer)n).intValue();
System.out.println("Count total: " + sum);
}
}
class Semaphore {
private int permits = 0;
public Semaphore(int permits) {
this.permits = permits;
}
public synchronized void acquire() {
while (permits < 1) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("Error");
System.exit(-1);
}
}
permits--;
}
public void release() {
synchronized (this) {
permits += 1;
notifyAll();
}
}
}
I'm trying to stimulate the scenario of deadlocks in the shared array using Reentrant Locks.
class SharedArray {
private int ff[];
private Lock keys[];
public SharedArray(int n){
ff = new int[n];
keys = new ReentrantLock[n];
for(int j = 0; j < n; j++){
ff[j] = (int)(Math.random()*100);
keys[j] = new ReentrantLock();
}
}
void swap(int j, int k) {
keys[j].lock(); keys[k].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[j].unlock(); keys[k].unlock();
}
}
Here the swap method is deadlock prone which I have achieved. for example if Thread 1 is swap(7,4) and at the same time Thread 2 is swap(4,7) this will raised the deadlock.
How do I prevent it from deadlock. What sort of refactoring is required. I have tried to used synchronized but I'm looking for possibly a reliable way to solve that.
synchronized void swap(int j, int k) {
keys[j].lock(); keys[k].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[j].unlock(); keys[k].unlock();
}
How do I prevent it from deadlock?
One way to prevent deadlock would be to ensure that any threads that acquire the same two locks always will acquire them in the same order.
void swap(int j, int k) {
int first = Math.min(j, k);
int second = Math.max(j, k);
keys[first].lock(); keys[second].lock();
int t = ff[j]; ff[j] = ff[k]; ff[k] = t;
keys[second].unlock(); keys[first].unlock();
}
You want to employ lock ordering. If you lock each time in a predictable order you can prevent dead locking.
Found in Java Concurrency In Practice, you can see an example of how to achieve this:
public void transferMoney(final Account fromAcct, final Account toAcct, final DollarAmount amount)
throws InsufficientFundsException {
class Helper {
public void transfer() throws InsufficientFundsException {
if (fromAcct.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAcct.debit(amount);
toAcct.credit(amount);
}
}
}
int fromHash = System.identityHashCode(fromAcct);
int toHash = System.identityHashCode(toAcct);
if (fromHash < toHash) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
} else if (fromHash > toHash) {
synchronized (toAcct) {
synchronized (fromAcct) {
new Helper().transfer();
}
}
} else {
synchronized (tieLock) {
synchronized (fromAcct) {
synchronized (toAcct) {
new Helper().transfer();
}
}
}
}
}
https://pdfs.semanticscholar.org/3650/4bc31d3b2c5c00e5bfee28ffc5d403cc8edd.pdf, search for Listing 10.3. Inducing a Lock Ordering to Avoid Deadlock.
public class ThreadsDemo {
public static int n = 0;
private static final int NTHREADS = 300;
public static void main(String[] argv) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(NTHREADS);
for (int i = 0; i < NTHREADS; i++) {
new Thread(new Runnable() {
public void run() {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
n += 1;
cdl.countDown();
}
}).start();
}
cdl.await();
System.out.println("fxxk, n is: " + n);
}
}
Why the output is "n is: 300"? n isn't explicitly synchronized. And if I uncomment "Thread.sleep", the output is "n is: 299 or less".
I changed your code this way:
private static final int NTHREADS = 300;
private static AtomicInteger n = new AtomicInteger();
public static void main(String[] argv) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(NTHREADS);
for (int i = 0; i < NTHREADS; i++) {
new Thread(new Runnable() {
public void run() {
n.incrementAndGet();
cdl.countDown();
}
}).start();
}
cdl.await();
System.out.println("fxxk, n is: " + n);
}
You have to deal with racing-conditions. All the 300 threads are modifying n concurrently. For example: if two threads would have read and increment n concurrently than both increment n to the same value.
That was the reason why n wasn't always 300, you lost one increment in such a situation. And this situation could have occurred zero or many times.
I changed n from int to AtomicInteger which is thread safe. Now everything works as expected.
You better use AtomicInteger.
This question will help you with description and example: Practical uses for AtomicInteger
Static context need to have lock on the class and not on the Object. If you need a static variable to be synchronized and do not need it to be cached inside the thread locally you need to declare it as volatile.
public class ThreadsDemo {
public static int n = 0;
private static final int NTHREADS = 30;
public static void main(String[] argv) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(NTHREADS);
for (int i = 0; i < NTHREADS; i++) {
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < 1000; j++) // run a long time duration
n += 1;
cdl.countDown();
}
}).start();
}
cdl.await();
System.out.println("fxxk, n is: " + n);
}
}
output "n is: 29953"
I think the reason is, the threads run a short time duration, and the jvm don't make a context switch.
Java static field will be synchronized among threads?
No. You should make it volatile or synchronize all access to it, depending on your usage patterns.
I recently attended an interview where in a question was asked "Is it possible to improve the following code":
public class Performance{
static class C1 {
volatile long c1;
volatile long c2;
}
static C1 p = new C1();
static class Worker implements Runnable {
private static final int INT = Integer.MAX_VALUE / 8;
private final boolean b;
Worker(boolean b) {
this.b = b;
}
#Override
public void run() {
if (b) {
for (int i = 0; i < INT; i++) {
p.c1++;
}
} else {
for (int i = 0; i < INT; i++) {
p.c2++;
}
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Worker(true));
Thread t2 = new Thread(new Worker(false));
t1.start();
t2.start();
}
}
JIT compiler from java 7 is very smart. It removes or reorders of unused field. For avoiding false sharing you should add volatile key word.
Java 8 has new annotation #sun.misc.Contented. See http://shipilev.net/talks/jvmls-July2013-contended.pdf for more details
Padding variables can be an improvement, but since it is unknown (theoretically) on which platform your code eventually runs, you cannot be sure that padding will do the trick. There are processors that will gain a benefit from this, there are others that will slow down if you do.
This is such a deep micro-optimization that it is easy to break more than you fix. I would leave it to the JVM to decide how whether or not it wants to do that, unless this is an absolute must-have in a perfectly defined environment.
Btw. the most optimized version of that code above:
static class C1 {
final long c1 = Integer.MAX_VALUE >>> 3;
final long c2 = c2;
}
;)
My answer was, yes it is possible by using variable padding to avoid cache contention. This technique presented in Java 8 LongAdder class.
Padding is a strategy to reduce CPU cache contention by trying to make sure that different cells do not land in the same cache line.
public class Performance{
static class C1 {
volatile long c1;
long q1, q2, q3, q4, q5, q6, q7, q8;
volatile long c2;
}
static C1 p = new C1();
static class Worker implements Runnable {
private static final int INT = Integer.MAX_VALUE / 8;
private final boolean b;
Worker(boolean b) {
this.b = b;
}
#Override
public void run() {
long start = System.currentTimeMillis();
if (b) {
for (int i = 0; i < INT; i++) {
p.c1++;
}
} else {
for (int i = 0; i < INT; i++) {
p.c2++;
}
}
long end = System.currentTimeMillis();
System.out.println("took: " + (end - start) + " " + p.c1 + p.c2);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Worker(true));
Thread t2 = new Thread(new Worker(false));
t1.start();
t2.start();
}
}
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.