My test program asks for a string and prints it every 2 seconds. I've read some already about java memory model or how threads don't immediately update their variables on the main memory.
I've tried with volatile and static attributes. Synchronizing code blocks in which the variable line was modified. With wait()/notifi() when the variable was changed and some others. How do I assign line as a reference and not as value? Am I using the methods I tried wrong? Why can objects stay perfectly synchronized when they act as monitors but they can't be when acting as pointers?
public class TestSharedVariable {
static String line= "";
public static void main(String[] args) {
// For reading from keyboard
Scanner keyboard = new Scanner(System.in);
Printer p = new Printer(line);
p.start();
// Reads a line from keyboard into the shared variable
while(!line.equals("quit")){
line = keyboard.nextLine();
}
}
}
class Printer extends Thread{
private volatile String line;
public Printer(String palabra){
this.line = palabra;
}
/* Prints the line each 2 sec */
#Override
public void run(){
while(!line.equals("quit")){
try {
sleep(2000);
} catch (InterruptedException e) {e.printStackTrace();}
System.out.println(this.getName() + ": " + line);
}
}
}
Output:
Thread-0:
asdf
Thread-0:
Thread-0:
You have two main issues:
For one Strings are immutable, and so you cannot change the state of a String variable, such as the characters that comprise it, once it has been created, and
You are assigning two reference variables to the same object, but are expecting one variable to change its assignment if the other variable's assignment changes, and this isn't how Java reference variables work.
In other words, even though you're initially setting the Printer object's line variable to the same reference as the TestSharedVariable's static line variable, changing the TestSharedVariable's static line variable's reference later will have no effect on Printer line variable's reference assignment. This has nothing to do with threading and all to do with understanding reference variables. Think of reference variables like pointers in C or other similar languages. If two variables point to the same object, changing one variable to point to a different object will have no effect on the first variable.
For your code to work, both variables must share a reference to the same mutable object, and you must change the state of the mutable object, not the reference to it.
For e.g.,
import java.util.Scanner;
public class TestSharedVariable {
static volatile MutableObject mutableObject = new MutableObject();
public static void main(String[] args) {
// For reading from keyboard
Scanner keyboard = new Scanner(System.in);
Printer p = new Printer(mutableObject);
new Thread(p, "Print thread").start();
// Reads a line from keyboard into the shared variable
while (!mutableObject.getData().equals("quit")) {
mutableObject.setData(keyboard.nextLine());
}
}
}
class Printer implements Runnable {
private volatile MutableObject mutableObject;
public Printer(MutableObject mutableObject) {
this.mutableObject = mutableObject;
}
/* Prints the line each 2 sec */
#Override
public void run() {
while (!mutableObject.getData().equals("quit")) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + ": " + mutableObject);
}
}
}
class MutableObject {
private String data = "";
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#Override
public String toString() {
return data;
}
}
Related
I want to make an object in a new thread, that will create another thread. In that last created threads I need a reference for variable from exact object that created this thread. So far I have this code:
Main
public static void main(String[] args) {
for(int i = 0; i < 2; i++){
ClassThread ct = new ClassThread();
Thread t = new Thread(ct);
t.start();
}
}
ClassThread
public static volatile int liczba = 1;
private static int id = 0;
#Override
public void run() {
for(int i = 0; i < 2; i++){
Class1 cla = new Class1(liczba, id);
Thread t = new Thread(cla);
t.start();
id++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Class1
private volatile int var;
private int id;
public Class1(int _var, int _id) {
var = _var;
id = _id;
}
#Override
public void run() {
while(true){
System.out.println("Thread: " + id + " : " + var);
var++;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
If you need to get an int reference from one thread to another, you either have to specify your own MutableInteger class, or use AtomicInteger. The atomic integer has the positive side-effects in that operations can be made atomic. For a more exhaustive answer, see This answer.
If the question is regarding non-primitive types, you can simply pass the needed reference to the constructor as you are already attempting to do. Any changes to the internal state of that object will be reflected to all holders of a reference. Some objects are immutable (String being the perhaps most well-known, but be aware that Integer, Long, etc. works the same way.), and can therefore not be used in this way.
Do note that if you pass a reference, any assignments done to your internal reference var = "hello"; will not affect anything outside your class. You will simply exchange your private reference for another one, leaving all other references to the old object as they are. This has to do with the fact that Java is always pass-by-value.
This question already has answers here:
Synchronizing on an Integer value [duplicate]
(9 answers)
Closed 7 years ago.
takeAmount and addAmount is simply to add/sub value from balanceAccount(eg. add 11,12...,20 or add 101,102...,110). balanceAccount have two version one is using synchronized function and other is using synchronized block.
Is that any different between BalanceAccount_synchronizedBlock and BalanceAccount_synchronizedFunction?
Indeed BalanceAccount_synchronizedFunction always return 0, while BalanceAccount_synchronizedBlock doesn't.
And...why it will show different behavior?
public class mainStart {
public static void main(String args[])
{
for (int i=1;i<3000;i=i+10)
{
new Thread(new addAmount(i)).start();
new Thread(new takeAmount(i)).start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//BalanceAccount_synchronizedBlock.printAmount();
BalanceAccount_synchronizedFunction.printAmount();
}
}
class takeAmount implements Runnable {
private int startFrom;
public takeAmount(int start)
{
this.startFrom=start;
}
public void run()
{
for (int i=startFrom;i<startFrom+10;i++)
//BalanceAccount_synchronizedBlock.sub(i);
BalanceAccount_synchronizedFunction.sub(i);
}
}
class addAmount implements Runnable {
private int startFrom;
public addAmount(int start)
{
this.startFrom=start;
}
public void run()
{
for (int i=startFrom;i<startFrom+10;i++)
//BalanceAccount_synchronizedBlock.add(i);
BalanceAccount_synchronizedFunction.add(i);
}
}
public class BalanceAccount_synchronizedBlock {
public static Integer amount=0;
public static void add(int a)
{
synchronized (amount)
{
amount = amount + a;
}
}
public static void sub(int a)
{
synchronized (amount)
{
amount = amount - a;
}
}
public synchronized static void printAmount()
{
System.out.println("Amount " + amount);
}
}
public class BalanceAccount_synchronizedFunction {
public static Integer amount=0;
public synchronized static void add(int a)
{
amount = amount + a;
}
public synchronized static void sub(int a)
{
amount = amount - a;
}
public synchronized static void printAmount()
{
System.out.println("Amount " + amount);
}
}
Synchronizing a method uses the enclosing class as a synchronization token. When you write synchronized(amount) you are using an Integer instance as a synchronization token. As you are not using the same token in both cases, the lock will not occur as expected.
Also note that Integer is immutable, and every time you reassign a value into amount, you are creating a new instance an lose whatever lock you may have had on the previous value.
Your print method is defined as
public synchronized static void printAmount()
which is synchronized on the class itself. In the case of your "block" attempt, the blocks are synchronizing on amount, while the print method is synchronizing on the class. Change that method to use a block also synchronized on amount.
As Kayaman pointed out, you also have the problem that you're synchronizing on a variable (amount) whose referent is constantly changing. Instead, declare a private static final Object LOCK = new Object() that is used only for synchronization--or better yet, just use AtomicInteger.
You can either lock using object which is calling this method by using
synchronized (this) { // this is similar to method level synchronization
Or using another class level Object other then amount integer(as #Kayaman pointed out, it is immutable so every time new integer object is created when you update it)
public class BalanceAccount_synchronizedBlock {
public static Integer amount=0;
public static Object Lock = new Object();
public static void add(int a) {
synchronized (Lock) {
amount = amount + a;
}
}
I'm implementing a barrier in java that when accesed by a thread it creates a new object, with a value from the parameter, stored in a private variable to later be returned. Then, when another thread calls the barrier it completes the former object with this other parameter. The first pair goes on well, the rest receive the same object the first pair created.
private Barrier aBarrier;
private boolean first = true;
public synchronized Barrier pairUp(int id){
try{
if(first){
first = false;
aBarrier = new Barrier(); aBarrier.setFirst(id);
wait();
}
else{
first = true;
aBarrier.setLast(id);
notify();
}
}
catch(InterruptedException e){System.out.printf("ERROR");}
return aBarrier;
}
And this would be what every process calling the method above looks like.
private int id = ID OF THE PROCESS, 14 RUN CONCURRENTLY SO FROM 0 TO 13 (this is set in the constructor method);
public void run() {
while(true){
myBarrier = pairUp(id);
myBarrier.goThrough();
//Do stuff that doesn't matter here
// ....
}
}
A Barrier object contains two integers and a method to do more stuff later.
If I reset the private variable aBarrier to null before or after the calls it always gives null back.
I feel like I'm missing some stupid thing here.
If a process calls the method pairUp() after the first pair it will get the first Barrier.
I use this to diferentiate which process came first in the pairUp method.
Thanks beforehand!
A Barrier object contains two integers and a method to do more stuff later. If I reset the private variable aBarrier to null before or after the calls it always gives null back. I feel like I'm missing some stupid thing here.
I think the problem is that you are returning aBarrier after the wait/notify calls but it might have been changed by subsequent threads. Storing it in a local variable so it won't be changed is key.
You might also have had multiple versions of the wrapping object so your synchronized statement is synchronizing on a different object?
Couple things to note in the code below:
The System.out.println(...) changes the synchronization. Need to be careful here.
I used the aBarrier being null or not to replace the first boolean.
Code:
public class Foo implements Runnable {
private static int NUM_THREADS = 14;
private static final AtomicInteger idCounter = new AtomicInteger();
private static final ExecutorService threadPool = Executors.newFixedThreadPool(NUM_THREADS);
private static Barrier aBarrier = null;
public static void main(String[] args) {
// only 1 Foo object
Foo foo = new Foo();
for (int i = 0; i < NUM_THREADS; i++) {
threadPool.execute(foo);
}
}
public synchronized Barrier pairUp(int id) {
Barrier barrier = aBarrier;
try {
if (barrier == null) {
barrier = new Barrier();
barrier.first = id;
aBarrier = barrier;
wait();
} else {
barrier.last = id;
aBarrier = null;
notify();
}
} catch (InterruptedException e) {
// always a good pattern
Thread.currentThread().interrupt();
e.printStackTrace();
barrier = null;
}
// return local barrier because aBarrier might have changed
return barrier;
}
#Override
public void run() {
int id = idCounter.incrementAndGet();
while (true) {
Barrier myBarrier = pairUp(id);
// System.out.println is synchronized so it may move the bug
System.out.println(id + ": " + myBarrier.first + " and " + myBarrier.last);
}
}
private static class Barrier {
int first;
int last;
}
}
I have two methods: The first (MultiThreaded) waits for an input and depending on what you typed it prints 1, 2, 3, nothing or ends altogether. The second (Dumper) takes the current value of 1, 2 or 3 and prints it every 300ms (at least it should).
Both methods individually work fine (1 printing my desired value; 2 printing every 300ms), but I can't seem to get method 2 to take the value that method 1 just received, even though they are both running at the same time.
I searched for how to run both at the same time finding this, so I knew I had to use threads. Then how to use a variable from another method (or use one in both) finding this - however I guess the way I used volatile is not correct?
This is my code:
MultiThreaded.java
public class MultiThreaded extends Thread{
volatile int status ;
public static void main(String[] args) {
new MultiThreaded().execute_input();
}
public MultiThreaded() {
}
public void run() {
System.out.println("BEGIN");
while(true) new MultiThreaded().execute_input();
}
public void execute_input() {
int input;
while (true) {
try {
input = System.in.read();
} catch (Exception e) {input = 0;}
switch(input) {
case '1' :
case '2' :
case '3' :
status = input-'0';
System.out.print(status);
break;
case 'q': //End
return;
default:
}
}
}
}
Dumper.java
class Dumper extends Thread{
volatile int status;
public static void main (String[] args) {
new Dumper().run();
}
public void run() {
while(true) printName();
}
private void printName() {
System.out.print("[");
System.out.print(status);
System.out.println("]");
try { Thread.sleep(300); }
catch (Exception e) {}
}
}
Main.java
public class Main {
public static void main(String[] args) {
new MultiThreaded().start();
new Dumper().start();
}
}
I'm grateful for any advice as I am pretty lost at the moment. Many thanks in advance! :)
I don't see any part of your code that ensures that both threads share the same status: just because they have the same name doesn't mean they're the same variable.
What you've done so far is say, in code, "both classes have their own variable status, and it can be modified out of thread", but now you still need to write the code that ensures that the manipulation actually happens. For instance, you can use a setStatus(int s) method on the Dumper that the MultiTreaded instance can call, or you can even directly manipulate the dumper.status variable.
Whatever you go with, at least one thread needs to know the other exists. For instance:
public static void main(String[] args) {
Dumper device = new Dumper();
MultiThreaded master = new MultiThreaded(device);
master.start();
device.start();
}
and in the MultiThreaded class,
Dumper device;
...
public MultiThreaded(Dumper device) {
this.device = device;
}
public void execute_input() {
...
device.status = status;
}
To prove initialization safety for immutable objects, I wrote a small program. Even though fields were final, second thread was able to view the half-constructed object being created by the first thread. Have I got the concept wrong or "object escaping" can cause it? Second thread first printed "10 null" and then after half of the iterations it started printing "10 apple".
package test;
import java.util.ArrayList;
import java.util.List;
public final class ObjectEscape implements Runnable {
private final int a;
private final String b;
//this list is defined somewhere else
public static volatile List<ObjectEscape> globalList = new ArrayList<ObjectEscape>();
public ObjectEscape () throws InterruptedException {
a = 10;
globalList.add(this);
Thread.sleep(10);
b = "apple";
System.out.println("done");
}
public ObjectEscape(int a) {
this.a = 1;
b = "";
}
public static void main(String are[]) throws InterruptedException{
Thread t = new Thread(new ObjectEscape(1));
t.start();
ObjectEscape oe1 = new ObjectEscape();
}
#Override
public void run() {
int i=0;
while(i<10) {
if(globalList.get(0) != null)
System.out.println(globalList.get(0).a+" "+globalList.get(0).b);
i++;
}
}
}
final fields are guaranteed to have been initialized when the contructor call finishes. Naturally, a "leaking this" will subvert the value of this guarantee:
globalList.add(this); // ObjectEscape.<init> has not finished yet
See also: Java leaking this in constructor