I am new to multithreading. I have a volatile variable currentPrimeNo and it will print the next prime number as implemented in run method for every new thread. But everytime I am getting currentPrimeNo as 0 for every thread. How should I keep the global variable currentPrimeNo updated?
public class Processor implements Runnable {
private int id;
private static volatile int currentPrimeNo = 0;
public Processor(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Starting process id: " + id);
currentPrimeNo = Utils.generateNextPrime(currentPrimeNo);
System.out.println("Prime Number Associated with this thread is: " + currentPrimeNo);
System.out.println("Completed process id: " + id);
}
}
And the main class is:
public class MainClass {
@SuppressWarnings("resource")
public static void main(String[] args) {
System.out.println("****This is where the project starts*****");
Scanner reader = new Scanner(System.in);
System.out.print("Enter number of processes you want to create: ");
int n = reader.nextInt();
ExecutorService executor = Executors.newFixedThreadPool(n);
for(int i=1;i<=n; i++) {
executor.submit(new Processor(i));
}
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("****This is where the project ends*****");
}
}
Below is the generateNextPrime method from Util class:
public synchronized static int generateNextPrime(int currentPrime) {
int nextPrime = 2;
if (currentPrime <= 1) {
return nextPrime;
} else {
for (int i = currentPrime + 1;; i++) {
boolean notPrime = false;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
notPrime = true;
break;
}
}
if (notPrime == false) {
return i;
}
}
}
}
Below is the output I am getting:
****This is where the project starts*****
Enter number of processes you want to create: 4
Starting process id: 2
Starting process id: 3
Starting process id: 1
Starting process id: 4
Prime Number Associated with this thread is: 2
Prime Number Associated with this thread is: 2
Completed process id: 4
Completed process id: 1
Prime Number Associated with this thread is: 2
Completed process id: 2
Prime Number Associated with this thread is: 2
Completed process id: 3
****This is where the project ends*****
Since you have not shared the code for generateNextPrime
here, it would be a bit difficult to point out where exactly the code is failing.
There is an inherent problem associated with this.
Edit after Util.generateNextPrime() was added.
When we use volatile
keyword, all threads would see the current value and not the cached value of the variable. But in your code, volatile
variable is defined inside Runnable
implementation. Thus, it doesn't server for the purpose. It is true that run
method calls generateNextPrime
and passes the volatile
variable but what the called method actually sees and works on is a copy of the variable and not the exact variable (reading more on pass by value vs pass by reference will be beneficial to understand this better). The aim here is to have a single variable whose value should be altered by the generateNextPrime
call which will be done by each thread while running.
I moved the currentPrimeNo
definition to Util
class so that all threads see only one variable (and not a copy of it) and that too the real-time value of the volatile
variable. The method generateNextPrime
() was also altered a bit for sake of compactness. The output necessarily need not be in same order as you will not know the order of invocation of the worker threads.
Here is the code:
public class Processor implements Runnable {
private int id;
public Processor(int id) {
this.id = id;
}
@Override
public void run() {
System.out.println("Starting process id: " + id);
int currentPrimeNo = Utils.generateNextPrime();
System.out.println("Prime Number Associated with this thread " + id +" is: " + currentPrimeNo);
System.out.println("Completed process id: " + id);
}
}
public class Utils {
private static volatile int currentPrime = 0;
public static synchronized int generateNextPrime(){
currentPrime++;
if(currentPrime < 2){
currentPrime = 2;
return currentPrime;
}
for (int i = 2; i <currentPrime; i++) {
if(currentPrime%i == 0) {
currentPrime++;
i=2;
} else{
continue;
}
}
return currentPrime;
}
}
Output seen while benchtesting
Sample 1:
****This is where the project starts*****
Enter number of processes you want to create: 4
Starting process id: 3
Starting process id: 1
Starting process id: 2
Starting process id: 4
Prime Number Associated with this thread 3 is: 2
Prime Number Associated with this thread 1 is: 7
Completed process id: 1
Prime Number Associated with this thread 2 is: 3
Completed process id: 2
Prime Number Associated with this thread 4 is: 5
Completed process id: 3
Completed process id: 4
****This is where the project ends*****
Sample 2:
****This is where the project starts*****
Enter number of processes you want to create: 6
Starting process id: 5
Starting process id: 1
Starting process id: 3
Starting process id: 2
Starting process id: 4
Prime Number Associated with this thread 2 is: 7
Prime Number Associated with this thread 4 is: 11
Completed process id: 4
Prime Number Associated with this thread 1 is: 3
Completed process id: 1
Prime Number Associated with this thread 5 is: 5
Completed process id: 5
Prime Number Associated with this thread 3 is: 2
Starting process id: 6
Completed process id: 2
Prime Number Associated with this thread 6 is: 13
Completed process id: 6
Completed process id: 3
****This is where the project ends*****