I tried to print odd number in one thread and even number in another. I tried creating two thread and printing it in run method.
public class OddEven
{
private final int MAX = 10;
private static int counter = 0;
private volatile boolean isOdd = true;
public synchronized void printEven(int counter)
{
try {
if (!isOdd) {
System.out.println(Thread.currentThread().getName() + " " + counter);
counter++;
isOdd = true;
}
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized void printOdd(int counter)
{
if (isOdd) {
counter++;
System.out.println(Thread.currentThread().getName() + " " + counter);
isOdd = false;
}
notifyAll();
}
public static void main(String[] args) {
OddEven oddEven = new OddEven();
Thread th1 = new Thread() {
public void run() {
while (OddEven.counter < oddEven.MAX) {
oddEven.printEven(OddEven.counter);
}
}
};
th1.setName("even -");
th1.start();
Thread th2 = new Thread() {
public void run() {
while (OddEven.counter < oddEven.MAX) {
oddEven.printOdd(OddEven.counter);
}
}
};
th2.setName("odd -");
th2.start();
}
}
But it is printing it like below infinitely.
even - 0
odd - 1
even - 0
odd - 1
even - 0
odd - 1
To read: Is Java "pass-by-reference" or "pass-by-value"?
You pass in a primitive. counter++; makes sense only within the method and has no impact on the outer world. count refers to the method param, not to the field this.count.
There is no proper synchronisation placed upon the condition OddEven.counter < oddEven.MAX, so different things may happen.
My advice would be to remove isOdd and do a check on the spot. For instance,
public synchronized void printEven() {
if (counter % 2 != 0) {
System.out.println(Thread.currentThread().getName() + " " + ++counter);
}
}
The line oddEven.printEven(OddEven.counter) passes an integer by value to the printEven method which does not change the value of OddEven.counter when it does counter++ as also pointed in other answers here.
To get the desired output, one option is to remove the passed parameter to both printEven and printOdd methods. And there are many other ways to achieve what you are trying to do here.
And there is also a mistake in the printEven method. counter++; needs to be before the print statement.
This will give you the desired output.
Related
My first question, Thank for your help!
I'm trying to print odd and even numbers 1~100 alternatively using two threads.
Expected results:
pool-1-thread-1=> 1
pool-1-thread-2=> 2
pool-1-thread-1=> 3
pool-1-thread-2=> 4
......
pool-1-thread-1=> 99
pool-1-thread-2=> 100
I think i can use FairSync, but it can only guarantee that most of the print is correct. like this:
pool-1-thread-1=> 55
pool-1-thread-2=> 56
pool-1-thread-1=> 57
pool-1-thread-2=> 58
pool-1-thread-2=> 59 //※error print※
pool-1-thread-1=> 60
pool-1-thread-2=> 61
pool-1-thread-1=> 62
I don't know why is the order lost in very few cases?
You can criticize my code and my English.
Here is my code:
private static final int COUNT = 100;
private static final int THREAD_COUNT = 2;
private static int curr = 1;
static ReentrantLock lock = new ReentrantLock(true);
static ExecutorService executorService = Executors.newCachedThreadPool();
public static void main(String[] args) {
Runnable task = () -> {
for (; ; ) {
try {
lock.lock();
if (curr <= COUNT) {
System.out.println(Thread.currentThread().getName() + "=> " + curr++);
} else {
System.exit(0);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
};
for (int i = 0; i < THREAD_COUNT; i++) {
executorService.execute(task);
}
}
No dear your implementation is not correct. Which thread get's the opportunity to RUN is decided by the OS. Thread 1 & 2 will execute one after another cannot be guaranteed.
You can fix your code by checking the previous value of the variable curr and if the value is not what this thread expects don't increment and print.
for eg :
if(curr.threadName.equals("Thread 2") && (curr%2 !=0))
{
// Print
// Increment
}
You cant use single lock to achieve this. Even ReentrantLock gives fairness but it cant control thread schedule.
We can achieve throw inter thread communication like Semaphore. Semaphore controls the thread execution.
We create two threads, an odd thread, and an even thread. The odd thread would print the odd numbers starting from 1, and the even thread will print the even numbers starting from 2.
Create two semaphores, semOdd and semEven which will have 1 and 0 permits to start with. This will ensure that odd number gets printed first.
class SharedPrinter {
private Semaphore semEven = new Semaphore(0);
private Semaphore semOdd = new Semaphore(1);
void printEvenNum(int num) {
try {
semEven.acquire();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + num);
semOdd.release();
}
void printOddNum(int num) {
try {
semOdd.acquire();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + num);
semEven.release();
}
}
class Even implements Runnable {
private SharedPrinter sp;
private int max;
// standard constructor
#Override
public void run() {
for (int i = 2; i <= max; i = i + 2) {
sp.printEvenNum(i);
}
}
}
class Odd implements Runnable {
private SharedPrinter sp;
private int max;
// standard constructors
#Override
public void run() {
for (int i = 1; i <= max; i = i + 2) {
sp.printOddNum(i);
}
}
}
public static void main(String[] args) {
SharedPrinter sp = new SharedPrinter();
Thread odd = new Thread(new Odd(sp, 10),"Odd");
Thread even = new Thread(new Even(sp, 10),"Even");
odd.start();
even.start();
}
Refer : here
I want to implement simple threadsafe counter. The numbers are in the right order so that part is ok, the only problem is the condition is not always met and sometimes the numbers go up to 51 or 52.
Should I use the tag synchronized also around the while loop?
I mean, I can double check and put a condition in the method printAndIncrement but that doesn't seem very elegant.
public class MyCounter implements Runnable {
static int currentValue = 0;
private static synchronized void printAndIncrement() {
System.out.print(Thread.currentThread().getName() + ": " + currentValue + "\n");
currentValue++;
}
#Override
public void run() {
while (currentValue <= 50) {
printAndIncrement();
}
}
public static void main(String[] args) {
MyCounter counter = new MyCounter();
Thread thread1 = new Thread(counter);
Thread thread2 = new Thread(counter);
Thread thread3 = new Thread(counter);
thread1.start();
thread2.start();
thread3.start();
}
}
The check currentValue <= 50 and the call to printAndIncrement must be in the same synchronized block. Otherwise this problem is going to happen.
Let currentValue be 50. All three threads can do the check that the current value is no more than 50 and then try to call printAndIncrement(); simultaneously.
Due to the synchronized void printAndIncrement() the threads will execute this method sequentially, but for the first thread the currentValue will be 50, for the second thread it will be 51 and for the third thread it will be 52.
The problem is that your boundary check and the increment are not both synchronized, which defeats the point of synchronization altogether.
The best alternative I can suggest that allows both synchronizing read/update and allowing your loop to stop would be to make the incrementing method return a boolean:
/** Prints and increments, returning true if max value has not been reached */
private static synchronized boolean printAndIncrement() {
if(currentValue < 51) {
System.out.print(Thread.currentThread().getName()
+ ": " + currentValue + "\n");
currentValue++;
return true;
} else {
return false;
}
}
And change the run method to:
public void run() {
while (printAndIncrement()) {
//nothing needs to be done here
}
}
I am doing a sample program with wait() and notify(), but when notify() is called, more than one thread is wakes up instead of one.
The code is:
public class MyQueue<T> {
Object[] entryArr;
private volatile int addIndex;
private volatile int pending = -1;
private final Object lock = new Object();
private volatile long notifiedThreadId;
private int capacity;
public MyQueue(int capacity) {
entryArr = new Object[capacity];
this.capacity = capacity;
}
public void add(T t) {
synchronized (lock) {
if (pending >= 0) {
try {
pending++;
lock.wait();
System.out.println(notifiedThreadId + ":" + Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (pending == -1) {
pending++;
}
}
if (addIndex == capacity) { // its ok to replace existing value
addIndex = 0;
}
try {
entryArr[addIndex] = t;
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ARRAYException:" + Thread.currentThread().getId() + ":" + pending + ":" + addIndex);
e.printStackTrace();
}
addIndex++;
synchronized (lock) {
if (pending > 0) {
pending--;
notifiedThreadId = Thread.currentThread().getId();
lock.notify();
} else if (pending == 0) {
pending--;
}
}
}
}
public class TestMyQueue {
public static void main(String args[]) {
final MyQueue<String> queue = new MyQueue<>(2);
for (int i = 0; i < 200; i++) {
Runnable r = new Runnable() {
#Override
public void run() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
queue.add(Thread.currentThread().getName() + ":" + i);
}
}
};
Thread t = new Thread(r);
t.start();
}
}
}
After some time, I see two threads being wake up by single thread. The output looks like:
91:114
114:124
124:198
198:106
106:202
202:121
121:40
40:42
42:83
83:81
81:17
17:189
189:73
73:66
66:95
95:199
199:68
68:201
201:70
70:110
110:204
204:171
171:87
87:64
64:205
205:115
Here I see 115 thread notified two threads, and 84 thread notified two threads; because of this we are seeing the ArrayIndexOutOfBoundsException.
115:84
115:111
84:203
84:200
ARRAYException:200:199:3
ARRAYException:203:199:3
What is the issue in the program?
What is the issue in the program?
You have a couple of problems with your code that may be causing this behavior. First, as #Holder commented on, there are a lot of code segments that can be run by multiple threads simultaneously that should be protected using synchronized blocks.
For example:
if (addIndex == capacity) {
addIndex = 0;
}
If multiple threads run this then multiple threads might see addIndex == capacity and multiple would be overwriting the 0th index. Another example is:
addIndex++;
This is a classic race condition if 2 threads try to execute this statement at the same time. If addIndex was 0 beforehand, after the 2 threads execute this statement, the value of addIndex might be 1 or 2 depending on the race conditions.
Any statements that could be executed at the same time by multiple threads have to be properly locked within a synchronized block or otherwise protected. Even though you have volatile fields, there can still be race conditions because there are multiple operations being executed.
Also, a classic mistake is to use if statements when checking for over or under flows on your array. They should be while statements to make sure you don't have the class consumer producer race conditions. See my docs here or take a look at the associated SO question: Why does java.util.concurrent.ArrayBlockingQueue use 'while' loops instead of 'if' around calls to await()?
So I have been trying to sort this out for a couple of hours now and I'm sure its something really simple or just a simple mistake i am missing but i have a three class program, control, account and MyThreads.
Im trying to have multipule threads(cards) modify the single account, i'm trying to use a monitor so only one thread can make changes at a time, this is not what i have archived I have somehow just allowed the one thread to access the account class and no others, they seem to just disappear, i assume they are just all on wait but refuse to wake up... any help before i implode?
account code:
class account{
private static int value = 0;
private static int cards = 0;
private static int count = 0;
private static int lock = 0;
public void setValue(int temp){
value = temp;
}
public int getValue(){
// while(lock == 1){
// try{
// wait();
// }catch (InterruptedException e){
// }
// }
return value;
}
synchronized public void withdraw(int temp, String tempID){
while(lock == 1){
try{
wait();
}catch (InterruptedException e){}
}
lock=1;
value= value - temp;
count++;
System.out.println(count + "(" + tempID +")"+" "+temp+" - "+value);
lock = 0;
this.notifyAll();
}
synchronized public void deposit(int temp, String tempID){
while(lock == 1){
try{
wait();
}catch (InterruptedException e){}
}
lock=1;
value= value + temp;
count++;
System.out.println(count + "(" + tempID +")"+" - "+temp+" "+value);
lock = 0;
this.notifyAll();
}
public void setCards(int temp){
cards = temp;
}
public int getCards(){
return cards;
}
public int getCount(){
return count;
}
}
control code:
class control{
public static void main(String [] args){
account acc = new account();
acc.setValue(1000);
acc.setCards(5);
// if(args.length > 0){
// try{
// int tempCards = Integer.parseInt(args[0]);
//
// }catch (NumberFormatException e) {
// System.err.println("Number of Cards : " + args[0] + " must be an integer.");
// System.exit(1);
// }
// try{
// int tempVal = 0;
// tempVal = Integer.parseInt(args[1]);
// acc.setValue(tempVal);
// }catch (NumberFormatException e) {
// System.err.println("Account Value : " + args[1] + " must be an integer.");
// System.exit(1);
// }
// }else{
// System.err.println("No values found, please start program with the number of Cards and Bank Account Value, both in integer format");
// System.exit(1);
// }
System.out.println("Transaction Withdrawal Deposit Balance");
System.out.println(" " + acc.getValue());
for(int i=0; i<=((acc.getCards())-1); i++){
new MyThreads(Integer.toString(i+1));
}
}
}
MyThreads code:
class MyThreads implements Runnable{
private String ID;
private Thread t;
account acc = new account();
MyThreads(String tempID){
ID = tempID;
t = new Thread(this, ID);
t.start();
}
public void run(){
try{
for (int i = 0; i < 20; i++){
if(Math.random()>0.5){
int tempW = 0;
tempW = ((int)(Math.random()*100));
acc.withdraw(tempW, this.ID);
//System.out.println(acc.getCount() + "(" + this.ID +")"+" "+tempW+" -"+acc.getValue());
}else{
int tempD = 0;
tempD = ((int)(Math.random()*100));
acc.deposit(tempD, this.ID);
//System.out.println(acc.getCount() + "(" + this.ID +")"+" "+" - "+tempD+" "+acc.getValue());
}
t.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Thread " + ID + " interrupted.");
}
System.out.println("Thread " + ID + " exiting.");
}
}
I know its a mess, forgive me im lazy.
Have a look at the definition of a Monitor in Java. In your code, you use the keyword synchronized for two methods, which are the same as:
public void XX(){
lock.lock(); // lock is a private variable
try {
// code here
} finally {
lock.unlock();
}
}
In short, It is a shorthand for explicit locking and will prevent multiple threads to access the methods concurrently.
So, just remove the lock part (i.e. the while(lock==1) block) inside your synchronized methods and it will work. Also, if in other codes you need a real lock, use the Lock class, not an integer.
For more information, there are a lot of good introduction to multithreading on the web, for example this one.
Your question, and thus answer, is a wonderful mixture of static synchronized and wait-notify that's neve being called. Why use static? sounds like a magic word? skip static and make life easier.
Also note that a wait-notify is related to a specific object; if wait-notify are related to different objects they will not communicate. Have a single object that they all synchronize around.
I have an array with the size of n which is filled with the numbers 1..n.
I need to sum this array using m threads by each time taking two elements, sum them up and inserting the sum back to the array.
Here is what I tried to do.
The synchronized part first
public class MultiThreadedSum {
private ArrayBuffer ArrayBufferInst;
private int Sum;
private boolean Flag, StopFlag;
public MultiThreadedSum(ArrayBuffer ArrayBufferInst) {
this.ArrayBufferInst = ArrayBufferInst;
Sum = 0;
Flag = false;
StopFlag = false;
}
public synchronized void Sum2Elements() {
while(Flag){
try {wait();}
catch (InterruptedException e){}
}
Flag = true;
if (StopFlag) {
notifyAll();
return;
}
System.out.println("Removing and adding 2 elements.");
Sum = ArrayBufferInst.Sum2Elements();
notifyAll();
}
public synchronized void InsertElement() {
while(!Flag){
try {wait();}
catch (InterruptedException e){}
}
Flag = false;
if (StopFlag) {
notifyAll();
return;
}
System.out.println("Inserting the sum.");
ArrayBufferInst.InsertElement(Sum);
if (ArrayBufferInst.RetunrSize() == 1) {
StopFlag = true;
}
System.out.println(ArrayBufferInst);
notifyAll();
}
public boolean ReturnStopFlag(){
return StopFlag;
}
#Override
public String toString(){
return ArrayBufferInst.toString();
}
}
I've splitted the m threads to 2 groups, half of them will do the summarization and half will do the adding using wait and notify.
public class Sum2ElementsThread implements Runnable{
private MultiThreadedSum MultiThreadedSumInst;
public Sum2ElementsThread( MultiThreadedSum MultiThreadedSumInst){
this.MultiThreadedSumInst = MultiThreadedSumInst;
}
#Override
public void run() {
while(!MultiThreadedSumInst.ReturnStopFlag())
MultiThreadedSumInst.Sum2Elements();
}
}
public class InsertThread implements Runnable{
private MultiThreadedSum MultiThreadedSumInst;
public InsertThread( MultiThreadedSum MultiThreadedSumInst) {
this.MultiThreadedSumInst = MultiThreadedSumInst;
}
#Override
public void run() {
while(!MultiThreadedSumInst.ReturnStopFlag()) {
MultiThreadedSumInst.InsertElement();
}
}
}
Here is part of the main:
ArrayBufferInst = new ArrayBuffer(n);
System.out.println("The Array");
System.out.println(ArrayBufferInst);
MultiThreadedSumInst = new MultiThreadedSum(ArrayBufferInst);
ExecutorService Threads = Executors.newCachedThreadPool();
for (i = 0; i < m/2; i++)
Threads.execute( new Sum2ElementsThread(MultiThreadedSumInst) );
for (; i < m; i++)
Threads.execute( new InsertThread(MultiThreadedSumInst) );
Threads.shutdown();
while(!MultiThreadedSumInst.ReturnStopFlag()){}
System.out.println("The sum of the array is " + MultiThreadedSumInst);
And the buffer
public class ArrayBuffer {
private ArrayList<Integer> ArrayBufferInst;
public ArrayBuffer(int SizeOfBuffer){
int i;
ArrayBufferInst = new ArrayList<>(SizeOfBuffer);
for (i = 0; i < SizeOfBuffer; i++){
ArrayBufferInst.add(i, i+1);
}
}
public int Sum2Elements(){
if (ArrayBufferInst.size() < 2){
return -1;
}
return ArrayBufferInst.remove(0) + ArrayBufferInst.remove(0);
}
public void InsertElement(int Elem) {
ArrayBufferInst.add(Elem);
}
public int RetunrSize(){
return ArrayBufferInst.size();
}
#Override
public String toString() {
return ArrayBufferInst.toString();
}
}
My question is about the end of the main, sometimes the program stop, sometime it doesn't, I know all the threads are exiting the run method because I checked that.
Sometimes I see the The sum of the array is message, sometimes I don't.
Your problem lies here:
public synchronized void Sum2Elements() {
while(Flag){
try {wait();}
catch (InterruptedException e){}
}
Flag = true;
// rest of method omitted here
}
When this part of the program is executed for the first time Flag is false and the loop is ignored. All subsequent executions of this method will result in a deadlock since this is the only place where you set Flag to false.
Not even interrupting will work, since you have no break in your loop and after the interruption you just go on to the next cycle and wait() forever.
Oh and read this - Java is not c#
It is really a very long code for you task.
Maybe i can propose a different sollution.
You can just split array for m parts (m - is a number of threads) - and each thread would sum it`s own part. When summing is over in each Thread - just sum all part results.
Or maybe i didnt get your task correctly. Specify more details please (the full task).