Let say that I create an object and run it in a thread, something like this.
public class Main {
public static void main(String[] args) {
SomeClass p = new SomeClass (143);
p.start();
p.updateNumber(144);
}}
Is it possible to update the parameter passed in SomeClass with a methode updateNumber() as fallows:
# Updated
class SomeClass extends Thread {
volatile int number ;
SomeClass (int number ) {
this.number = number ;
}
public void run() {
while(t开发者_运维问答rue){
System.out.println(number);
}
}
public void updateNumber(int n){
number =n;
}
}
Result : 144 144 144 144 144 ...
Thanks
Yes, but you need to declare number
as volatile
, or (preferably) use an AtomicLong
instead of a long
.
Declare number as volatile
.
When is volatile needed ?
When multiple threads using the same variable, each thread will have its own copy of the local cache for that variable. So, when it's updating the value, it is actually updated in the local cache not in the main variable memory. The other thread which is using the same variable doesn't know anything about the values changed by the another thread. To avoid this problem, if you declare a variable as volatile, then it will not be stored in the local cache. Whenever thread are updating the values, it is updated to the main memory. So, other threads can access the updated value
One other option not mentioned and which is the option you should use instead of synchronization as mentioned above is the make use of the Concurrency package introduced by Doug Lee in Java 1.5.
Use the Atomic classes, these take care of all you concurrency woes. (well to a point)
Something like this:
private AtomicInteger number = new AtomicInteger(0);
public void updateNumber(int n) {
number.getAndSet(n);
}
public int getNumber() {
return number.get();
}
Java 1.6 AtomicInteger JavaDoc
Java Concurrency in Practice
In my opinion the Java Concurrency in Practice is the best book on threading in Java
SomeClass
even it is Runnable, it is just a normal class and objects of it can be accessed by any thread that has reference to it. In your example. you are not calling updateNumber()
form anywhere, but if you call it after p.start(), you are acessing it from the thread that actually made the instance. If you are calling updateNumber()
in run()
, then you are accessing it from the thread you've just started.
The other question is: is it safe in your setup to change it form multiple threads? the answer is no. You have to declare it as volatile
(let say), or synchronize
if you changing it based on current value. How and what to synchronize depends on what you are actually doing with it.
You can use the keyword volatile
when all the following criteria are met:
- Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value
- The variable does not participate in invariants with other state variables
- Locking is not required for any other reason while the variable is being accessed
Otherwise, I'd recommend using some sort of synchronization policy
class SomeClass implements Runnable {
private Integer number;
SomeClass (int number) {
this.number = Integer.valueOf(number);
}
@Override
public void run() {
while(true){
System.out.println(getNumber());
}
}
public void updateNumber(int n){
synchronized(number){
number = Integer.valueOf(n);
}
}
public int getNumber(){
synchronized(number){
return number.intValue();
}
}
}
Yes, you can just call p.updateNumber(...)
but you will need to be careful of thread synchronization issues.
精彩评论