multi-threading: thread gets own copy of method, but parameter is shared - java

I want to confirm my understanding on this -
public class Main {
private static int j = 0;
private int k = 0;
public static void main(String[] args) {
Main obj = new Main();
obj.doProcess();
}
public void doProcess() {
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 4; i++) {
service.submit(new SingleProcessor());
}
}
public static void myStaticMethod() {
System.out.println("my static method");
int i = 0;
i++;
j++;
System.out.println("i " + i);
System.out.println("j " + j);
}
public void myInstanceMethod() {
System.out.println("my instance method");
int i = 0;
i++;
k++;
System.out.println("k " + k);
}
private class SingleProcessor implements Runnable {
#Override
public void run() {
System.out.println("single run starts" + Thread.currentThread().getName());
myStaticMethod();
myInstanceMethod();
}
}
}
When a thread runs, it gets it's own copy of methods, be it static or instance method - any variable created inside these methods are local and specific to that thread. It's like multiple 'instances' of this method are getting executed simultaneously, any variable created inside is not shared (it's local).
However parameters (static or instance) are shared by threads.
So in above example -
i is local and specific to thread.
j is shared.
k is shared.
output -
single run startspool-1-thread-1
single run startspool-1-thread-2
my static method
single run startspool-1-thread-3
my static method
i 1
i 1
j 2
j 2
my instance method
my instance method
k 1
k 2
my static method
i 1
j 3
my instance method
k 3
single run startspool-1-thread-4
my static method
i 1
j 4
my instance method
k 4
Is my understanding 100% correct? Anyone would like to put it in better words?
Thanks.

If I followed correctly-- that should be correct.
Its the basic understanding of stack vs heap. Anything declared on the stack (variables declared in a function) is only available locally. Variables declared on the heap can be access globally or by any function within its scope.
So if you have a thread processing a function all the variables inside the function can only be accessed within that function. BUT if you have a global variable and two threads both threads can access that variable. The catch is that you have to make sure they don't override one another if they write to that variable.
The solution for this is locking a heap variable while one thread is read/writing to it and then unlocking it when its done.

What do you think would happen if you run the code below? You'll see a similar output, but in different order, probably. i is a static variable and is in static scope, j is in method scope, k is an instance variable of Main. Same stuff with threads. Scopes work the same with threads. You should read about inner classes instead.
public class Main {
private static int j = 0;
private int k = 0;
public static void main(String[] args) {
Main obj = new Main();
obj.doProcess();
}
public void doProcess() {
for (int i = 0; i < 4; i++) {
SingleProcessor sp = new SingleProcessor();
sp.run();
}
}
public static void myStaticMethod() {
System.out.println("my static method");
int i = 0;
i++;
j++;
System.out.println("i " + i);
System.out.println("j " + j);
}
public void myInstanceMethod() {
System.out.println("my instance method");
int i = 0;
i++;
k++;
System.out.println("k " + k);
}
private class SingleProcessor implements Runnable {
#Override
public void run() {
System.out.println("single run starts" + Thread.currentThread().getName());
myStaticMethod();
myInstanceMethod();
}
}
}

You're right.
A static variable could be intrepreted as a Singleton in your application, no matter how many Threads you have, they'll always have a reference to the same variable.
As for your instance variable 'k', it only works because your nested class is not static, which means you need an instance of Main to be able to instanciate SingleProcessor. Your instance of SingleProcessor will, under the hood' have a hidden variable referencing you Main instance. It's the same as if you'ld write this:
public class SingleProcessor implements Runnable {
private Main main;
public SingleProcessor(Main main){
this.main = main;
}
#Override
public void run() {
System.out.println("single run starts" + Thread.currentThread().getName());
Main.myStaticMethod();
this.main.myInstanceMethod();
}
}
And give all of your SingleProcessor the same Main instance.
All of this is dangerous, a Thread may acquire a variable the same time another Thread is modifying it. There's alot of advanced topics about Thread safety. For simple types, you can use Atomic variables, se Concurrency package JavaDoc.

Related

Adding numbers using multiple threads in java

I am having trouble figuring out what my code is doing as this is my first time coding using multiple threads. To start off, in attempt to learn this type of programming I decided to write a miniature program that uses 8 threads to sum a number. However, no matter what I do it seems as if my program never stops when count = 10, it continues onward. I am using 8 threads as I planned on expanding my program to do large calculations. However, these threads are not correlating at all. They are going way past 10. I have used a synchronized method. I have tried a lock. I have tried implementing both at the same time. No matter what, it appears as if the threads still calculate past 10. See below for my current code.
public class calculator implements Runnable {
static int counter = 0;
static int sum = 0;
private synchronized static int getAndIncrement()
{
// System.out.println("counter is : " + counter);
int temp = counter;
counter = counter + 1;
System.out.println("counter is now : " + counter);
return temp;
}
private synchronized void addToSum(int value)
{
// System.out.println("sum : " + sum + " value: " + value);
sum += value;
}
#Override
public void run()
{
// TODO Auto-generated method stub
while(counter < 10)
{
int tempVal = getAndIncrement();
System.out.println("temp val : " + tempVal);
addToSum(tempVal);
// System.out.println("sum is now : " + sum);
}
}
}
This is my main method:
public static void main(String[] args)
{
calculator[] calc = new calculator[8];
Thread[] thread = new Thread[8];
final long startTime = System.currentTimeMillis();
for(int i = 0; i < 8; i++)
{
calc[i] = new calculator();
thread[i] = new Thread(calc[i]);
thread[i].start();
}
while(thread[0].isAlive() ||thread[1].isAlive() || thread[2].isAlive() || thread[3].isAlive() || thread[4].isAlive() || thread[5].isAlive() || thread[6].isAlive() || thread[7].isAlive())
{}
final long endTime = System.currentTimeMillis();
System.out.println(calculator.sum);
System.out.println("Execution time : " + (startTime - endTime));
}
I appreciate the help!
The synchronized keyword takes the object
lock. This means that two methods that are synchronized cannot execute on the same object. They will, however, execute concurrently on invocation on 2 different objects.
In your example, your code had 8 objects of calculator. The synchronized methods do not help you. Each thread uses it's separate object. You can completely remove the synchronized keyword, and your code will be semantically equivalent.
To avoid this, use the atomic version of the objects (AtomicInt) or lock on the objects themselves: synchronized(counter){...} but for this to work you will have to change the type to Integer.
I've just tested your sample and found the addToSum method doesn't work as expected here with heavy multi-thread, even if synchronized keyword is present.
Here, as sum variable is static, the method can be made static too.
After adding the static keyword, the behavior is as expected:
private static synchronized void addToSum(int value)
{
sum += value;
}
Here a simple test (addToSum replaced by incSum for simplicity) :
class IncrementorThread implements Runnable {
private static int sum = 0;
private static synchronized void incSum()
{
sum ++;
}
public void run() {
incSum();
Thread.yield();
}
}
void testIncrementorThread1() {
ExecutorService executorService = Executors.newCachedThreadPool();
//ExecutorService executorService = Executors.newSingleThreadExecutor() // result always ok without needing concurrency precaution
for(int i = 0; i < 5000; i++)
executorService.execute(new IncrementorThread());
executorService.shutdown();
executorService.awaitTermination(4000, TimeUnit.MILLISECONDS);
System.out.println("res = "+IncrementorThread.sum); // must be 5000
}
Result must be 5000, which is not the case if we remove the static keyword from the method incSum()

volatile example (that in JLS8/8.3.1.4 volatile Fields) not work?

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.3.1.4
Java Language Specification 8/8.3.1.4 volatile Fields
volatile example
Question:
In the example of volatile, I add synchronized keyword to method two() to avoid executing one() during method two().
But I still noticed j is larger than i: why ?
Note:
I use Java HotSpot 1.8.0_112.
If you can not noticed j is larger than i, please set testVolatile()/num to a larger number.
My demo:
public class VolatileDemo {
static volatile int i = 0, j = 0;
static void one() {
i++;
j++;
}
static synchronized void two() {
if (i != j)
System.out.println("i=" + i + " j=" + j);
}
static void testVolatile() {
int num = 5000;
for (int i = 0; i < num; i++) {
new Thread(new Runnable() {
public void run() {
one();
}
}).start();
}
for (int i = 0; i < num; i++) {
new Thread(new Runnable() {
public void run() {
two();
}
}).start();
}
}
public static void main(String[] args) {
testVolatile();
}
}
My result:
i=4996 j=4998
i=4998 j=5000
i=4998 j=5000
....
It's possible and it's described in the link you mentioned. It's at the end of the paragraph.
It is possible, however, that any given invocation of method two might observe a value for j that is much greater than the value observed for i, because method one might be executed many times between the moment when method two fetches the value of i and the moment when method two fetches the value of j.
So two() method reads i and then j with the exact order as in your code. But there are a cople of one() method calls between that reads which gives the result of (4998, 5000)

Reflect changes made to a shared variable between two threads ,immediately as it is updated

these are just sample codes to ask my question the other statements are omitted
here the instance of NewClass is being passes both to Foot and Hand objects
and hence all the instances NewClass,foot and hand share the variable sno of NewClass.
public class NewClass {
volatile int sno = 100;
public static void main(String args[])
{
NewClass n = new NewClass();
Foot f = new Foot(n);
Hand h = new Hand(n);
f.start();
h.start();
}
}
public class Foot implements Runnable{
Thread t;
NewClass n;
public Foot(NewClass n)
{
this.n = n;
}
public void run(){
for(int i=0;i<100;i++)
{
System.out.println("foot thread "+ i+" "+n.sno);
n.sno=(-1)*n.sno;
Thread.sleep(1); // surrounded by try-catch
}
}
}
public class Hand implements Runnable {
Thread t;
NewClass n;
public Hand(NewClass n)
{
this.n = n;
}
public void run(){
for(int i=0;i<100;i++)
{
System.out.println("hand thread "+ i+" "+n.sno);
n.sno=(-1)*n.sno;
Thread.sleep(1); // surrounded by try -catch
}
}
}
here the sign of seq.no is changing everytime but when used by the other thread the change is many times not reflected as if the updation is taking time.so please help ,
It is not taking to long to update.
System.out.println("foot thread " + i + " " + n.sno);
n.sno=(-1)*n.sno;
When you have this happening in two threads running in parallel they may be watching the value as positive at the same time. So they both change the value to negative. If you want to control the change you need a semaphore.
In NewClass:
volatile int sno = 100;
final Object semaphore = new Object();
And in your two Runnables:
synchronized (n.semaphore) {
System.out.println("foot thread " + i + " " + n.sno);
n.sno = (-1) * n.sno;
}

Passing value from inside while loop to different class

So let's say I have a main class with a while loop:
public class Main {
public static void main(String[] args) throws InterruptedException {
int one = 1;
int counter = 0;
while (one<100){
Thread.sleep(1000);
counter += 1;
Function.Move();
one++;
}
The counter variable in this loop is counting each second elapsed.
There is a separate class called Function:
public class Function {
public static int Move (int result){
result = 1 + counter;
return result;
}
}
So as you can see, inside the Function class's Move method, I want to be able to use the counter variable's new value, which increases with each passing second, to calculate the value of a different variable which will then be returned to the main method.
The problem is that I can't figure out how to pass the value of counter to the Move method inside the Function class to begin with.
I'm not shure if i understand what you want to do correctly, depending on where exactly you will need that result variable later i think your coude should look something like this:
public class Main {
int counter;
public static void main(String[] args) throws InterruptedException {
int one = 1;
counter = 0;
while (one<100){
Thread.sleep(1000);
counter += 1;
one++;
}
}
public int getCounter() {
return counter;
}
}
public class Function {
public static int move (int result, Main main){
result = 1 + main.getCounter();
return result;
}
}
You can use Function.move() anywhere you need it's value in your Programm now.
Beware, though, that you will need your code using the Function.move() to run in a different Thread as the Main Thread. Otherwise it will always return 101 or 1, as the while loop will always be running before or after your call to Function.move(), depending on where you call it (except if you call it from within the while loop, but then you counld just use counter++ without the need to have an extra class)

Java multithreading not thread-safe using synchronized

A simple multithreading test with synchronization. I thought if it was "synchronized," other threads would wait. What am I missing?
public class MultithreadingCounter implements Runnable {
static int count = 0;
public static void main(String[] args) {
int numThreads = 4;
Thread[] threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++)
threads[i] = new Thread(new MultithreadingCounter(), i + "");
for (int i = 0; i < numThreads; i++)
threads[i].start();
for (int i = 0; i < numThreads; i++)
try {
threads[i].join();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void run() {
increment();
}
public synchronized void increment(){
System.out.print(Thread.currentThread().getName() + ": " + count + "\t");
count++; // if I put this first or increment it directly in the print line, it works fine.
}
}
I thought this would display something like:
0: 1 2: 0 1: 2 3: 3
But its actual output:
0: 0 2: 0 1: 0 3: 3
and other variations like this. It should display each increment (i.e. 0,1,2,3) not in order...
Your synchronized keyword is on an instance method. No two threads can execute this method of one of your thread objects at the same time. But, that is not what your code does. Each thread executes the method on its own instance. The synchronization does not do what you seem to intend. If it were a static method, it would.
Your increment method should be static:
public static synchronized void increment() {
Right now, each object is synchronized on that individual instance, but since count is a static variable, you should be synchronizing on the Class object itself.
when synchronized keyword is used before a method, it ensures that that method can be executed by only one thread at a time with respect to that object only. It does not ensure thread safety from other objects.

Categories