Knowing that
Reads and writes are atomic for all variables declared volatile
Question1: Can this be understood as if
private volatile int x = 0;
x++; operation is atomic?
And that
Marking variable volatile does not eliminate all need to synchronize
atomic actions, because memory consistency errors are still possible.
Question2: I wonder under what circumstances (if any) it is possible to see a variable marked volatile and not see any methods of blocks marked synchronized (that attempt to access/ modify the variable)?
In other words, should all variables that need to be protected from concurrent modification be marked volatile?
The volatile only gives you additional visibility guarantees, atomic writes/reads for longs/doubles (otherwise not guaranteed by the JLS, yes) and some memory order guarantees. No synchronization (it is possible though to build synchronization blocks starting with just volatile - Dekker's algorithm )
So no, it does not help you with x++ - that's still a read, inc and write and needs some form of synchronization.
One example of volatile is the famous double-checked locking, where we avoid synchronization most of the time because the ordering guarantees are all we need:
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null) {
helper = new Helper();
}
}
}
return helper;
}
An example where there's absolutely no synchronization involved, is a simple exit flag, here it's not about ordering guarantees but only about the guaranteed visibility
public volatile boolean exit = false;
public void run() {
while (!exit) doStuff();
// exit when exit set to true
}
If another thread sets exit = true the other thread doing the while loop is guaranteed to see the update - without volatile it may not.
x++; operation is atomic?
No. This reduces to x = x + 1. The read of x is atomic, and the write to x is atomic, but x = x + 1 as a whole is not atomic.
I wonder under what circumstances (if any) it is possible to see a variable marked volatile and not see any methods of blocks marked synchronized (that attempt to access/ modify the variable)?
Well, there are all kinds of approaches to concurrency that don't use synchronized. There's a wide variety of other locking utilities in Java, and lock-free algorithms that still require things like volatile: ConcurrentLinkedQueue is a specific example, though it makes extensive use of "magical" compareAndSet atomics.
As a quickly testable example that may illustrate the previous answers, this yields always a final count of 8:
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadTest_synchronize {
public static void main(String[] args) {
ThreadTest_synchronize tt = new ThreadTest_synchronize ();
try {
tt.go();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void go() throws InterruptedException{
MyRunnable t = new MyRunnable();
Thread myThread_1 = new Thread( t, "t1");
Thread myThread_2 = new Thread( t, "t2");
myThread_1.start();
myThread_2.start();
myThread_1.join();
myThread_2.join();
System.out.println("Processing count="+t.getCount());
}
private class MyRunnable implements Runnable{
private AtomicInteger count=new AtomicInteger(0);
#Override
public void run() {
for(int i=1; i< 5; i++){
doSomething(i);
count.getAndAdd(1);
}
}
public AtomicInteger getCount() {
return this.count;
}
private void doSomething(int i) {
try {
Thread.sleep(i*300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
while this generally does not:
public class ThreadTest_volatile {
public static void main(String[] args) {
ThreadTest_volatile tt = new ThreadTest_volatile ();
try {
tt.go();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void go() throws InterruptedException{
MyRunnable t = new MyRunnable();
Thread myThread_1 = new Thread( t, "t1");
Thread myThread_2 = new Thread( t, "t2");
myThread_1.start();
myThread_2.start();
myThread_1.join();
myThread_2.join();
System.out.println("Processing count="+t.getCount());
}
private class MyRunnable implements Runnable{
private volatile int count = 0;
#Override
public void run() {
for(int i=1; i< 5; i++){
doSomething(i);
count++;
}
}
private int add(int count){
return ++count;
}
public int getCount(){
return count;
}
private void doSomething(int i) {
try {
Thread.sleep(i*300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Related
I'm new to threads. I wanted to get two threads to increment an integer to a certain value. because int type is immutable, I switched to atomic integer. I also tried to wrap an int to a class and that didn't work either. I also tried static/volatile int and that didn't work. I also tried to use fairness policy. The main issue is that "counterObj" is not incremented correctly and is still set to 0 even though it is injected to both threads.
My expected running behavior:
thread value
thread 0 0
thread 1 1
thread 0 2
...
What I wrote so far:
import java.util.concurrent.atomic.AtomicInteger;
public class Application {
public static void main(String[] args) {
Application app = new Application();
try {
app.launch();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void launch() throws InterruptedException {
int increments = 100;
AtomicInteger counterObj = new AtomicInteger(0);
CounterThread th1 = new CounterThread("1", counterObj, increments);
CounterThread th2 = new CounterThread("2", counterObj, increments);
th1.start();
th2.start();
System.out.println(counterObj.get());
}
}
and
import java.util.concurrent.atomic.AtomicInteger;
public class CounterThread implements Runnable {
private final String threadID;
private AtomicInteger counterObj;
private int bound;
public CounterThread(String threadID, AtomicInteger counter, int bound) {
this.threadID = threadID;
this.counterObj = counter;
this.bound = bound;
}
#Override
public synchronized void run() {
while (counterObj.get() < bound) {
synchronized (this) {
counterObj.incrementAndGet();
}
}
System.out.println("Thread " + threadID + " finished");
}
public void start() throws InterruptedException {
Thread thread = new Thread(this, threadID);
thread.join();
thread.start();
}
}
Cheers!
I think your program is exiting before your threads get a chance to do anything (probably due to the ordering of your starts and joins. I would move your thread starting logic into your main(or launch) method. Something like the following.
Thread thread1 = new Thread(new MyCounterRunnable("1", counterObj, increments));
Thread thread2 = new Thread(new MyCounterRunnable("2", counterObj, increments));
Then, in your main, you need to call join after starting the threads...as follows:
thread1.start(); // starts first thread.
thread2.start(); // starts second thread.
thread1.join(); // don't let main exit until thread 1 is done.
thread2.join(); // don't let main exit until thread 2 is done.
What you really are wanting is for only one thread to increment an int at a time.
The int variable is the resource you want in the synchronized block, so the different threads can increment it one at a time.
This can be done using syncrhonize alone.
Disclaimer: I didn't run the code so it could have some typo or Exceptions to be removed from the Application class.
public class Application {
private int theVar = 0;
private int increments = 100;
public static void main(String[] args) {
Application app = new Application();
try {
app.launch();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public synchronized addOne(){
this.theVar++;
}
private void launch() throws InterruptedException {
Runnable counter1 = new Counter(this, increments), counter2 = new Counter(this, increments);
Thread t1 = new Thread(counter1);
Thread t2 = new Thread(counter2);
t1.start();
t2.start();
}
}
A counter class
public class Counter implements Runnable{
private Application app;
int rounds = -1;
public Counter(Application app, rounds){
this.app = app;
this.rounds = rounds;
}
public void run(){
while(int i=0; i<rounds; i++){
this.app.addOne();
}
}
}
AtomicInteger takes care of atomicity itself, so you shouldn't need to use synchronized -- but only if you play by the rules, and do your atomic operations in one call.
You're failing to do this, because you call counterObj.get() then depending on the result counterObj.incrementAndGet(). You need to avoid this because you want the check and the update to be part of the same atomic chunk of work.
You can get close with:
while(counterObj.incrementAndGet() < bound) {} ;
But this will always increment at least once, which may be once too many.
Slightly more involved:
IntUnaryOperator incrementWithLimit = x ->
( x < bound ? x + 1 : x );
while(counterObj.updateAndGet(incrementWithLimit) < bound) {};
That is, we've created a function that increments a number only if it's lower than bound, and we tell AtomicInteger to apply that.
There are a couple of issues with your code:
Thread.join method works only if the thread has started, else it does nothing. So you must reorder your code, but if you just move the join method after start, when starting the first thread by calling CounterThread.start, the main thread will wait until the started thread has finished, blocked in the Thread.join method, and only then will continue to starting the second one. A solution is to make an additional method in the CounterThread class, that will be called after both threads have been started:
public void waitFinish() throws InterruptedException {
thread.join();
}
synchronized (this) is synchronizing on the CounterThread instance that has been created when you called new CounterThread(...), but you have two instances so each will be synchronizing on a different object. For synchronized to work, you need to use a common instance of an object, in this case you can use the shared counterObj.
Only the AtomicInteger methods are guaranteed to be thread safe, so after you check if the bound has been reached outside the synchronized block, when entering the synchronized block the value can already be changed by another thread. So you need to do a recheck inside the synchronized block OR to first synchronize on the shared lock(counterObj) before the check and increment.
while (true) {
synchronized (counterObj) {
if (counterObj.get() < bound)
counterObj.incrementAndGet();
else break;
}
}
Note that the AtomicInteger class synchronized methods aren't helping now, but because it is a mutable object, it helps to use it as a shared lock. If you used an Integer instead, being immutable, a new instance will have been created when you incremented it. So now, it's only function is a wrapper holding the integer result.
Putting it all together:
public class Application {
public static void main(String[] args) {
Application app = new Application();
try {
app.launch();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void launch() throws InterruptedException {
int increments = 100;
AtomicInteger counterObj = new AtomicInteger(0);
CounterThread th1 = new CounterThread("1", counterObj, increments);
CounterThread th2 = new CounterThread("2", counterObj, increments);
th1.start();
th2.start();
th1.waitFinish();
th2.waitFinish();
System.out.println(counterObj.get());
}
}
public class CounterThread implements Runnable {
private final String threadID;
private AtomicInteger counterObj;
private int bound;
private Thread thread;
public CounterThread(String threadID, AtomicInteger counter, int bound) {
this.threadID = threadID;
this.counterObj = counter;
this.bound = bound;
}
#Override
public void run() {
while (true) {
synchronized (counterObj) {
if (counterObj.get() < bound)
counterObj.incrementAndGet();
else break;
}
}
System.out.println("Thread " + threadID + " finished");
}
public void start() throws InterruptedException {
thread = new Thread(this, threadID);
thread.start();
}
public void waitFinish() throws InterruptedException {
thread.join();
}
}
I've included a double check on the AtomicInteger, this appears to be what you've been trying to accomplish.
import java.util.concurrent.atomic.AtomicInteger;
public class DualCounters{
public static void main(String[] args) throws Exception{
AtomicInteger i = new AtomicInteger(0);
int bounds = 3;
Thread a = new Thread(()->{
int last = 0;
while(i.get()<bounds){
synchronized(i){
if(i.get()<bounds){
last = i.getAndIncrement();
}
}
}
System.out.println("a last " + last);
});
Thread b = new Thread(()->{
int last = 0;
while(i.get()<bounds){
synchronized(i){
if(i.get()<bounds){
last = i.getAndIncrement();
}
}
}
System.out.println("b last " + last);
});
a.start();
b.start();
a.join();
b.join();
System.out.println(i.get() + " afterwards");
}
}
The double check is a broken concept in java, the AtomicInteger offers tools for accomplishing this without any synchronization.
int a;
while((a = i.getAndIncrement())<bounds){
...
}
Now a will never be greater than bounds inside of the while loop. When the loop is finished i and a could have a value greater than bounds.
If that was an issue, there is always the other method getAndUpdate
while((a = i.getAndUpdate(i->i<bounds?i+1:i)<bounds){
...
}
right now i'm trying to get my head arround threads and concurrency,
so i tried to make multiple threads which counts together to 1000.
Example: Thread 1=0, Thread 2=1.Thread 3=2, and so on
As you will see in the code i implemented the Runnable interface and started the threads.
What i can see is that every thread starts the loop only for itself even if i use a synchronized method.
This is the loop "class"
private String threadname;
private int counter;
Task3(String threadname,int counter) {
this.threadname = threadname;
this.counter =counter;
}
private synchronized void compute(int i) {
try {
// "simulate" computation
System.out.println(threadname);
Thread.sleep(100);
System.out.println(" " + i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
for(int i=0; i <= counter;i++)
compute(i);
}
and in this class i start 4 threads with a for loop and give the method aboce the parameters which is only the thread name and how often they should count...
for(int i=0; i<=3;i++){
Runnable r =new Thread(new Task3("Thread"+i,1000));
Thread t = new Thread(r);
t.start();
}
thanks in advance
Explanation
Synchronized only means that it is ensured that a thread waits before entering the method until another thread has finished executing this method. This means that only one thread, at one time, can be inside of this synchronized method.
This can prevent strange behavior when using non-atomic operations. For example threads catching outdated values, thinking they would be up-to-date.
Solution
If you want that all threads count together you need some kind of shared resource, i.e. the counter. Currently every thread has his own counter. You need one counter in total which is shared among all threads.
A quick and dirty method would be to make the counter static. But you can probably do better with a design like this:
Class which manages the threads:
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
for (int i = 0; i < 3; i++) {
Counter counter = new Counter(demo, 1000);
counter.start();
}
}
// Provide a shared resource for all threads
private int sharedCounter = 0;
// Provide a count method for all threads
// which is synchronized to ensure that no
// strange behavior with non-atomic operations occurs
public synchronized void count() {
sharedCounter++;
}
}
And the Thread class:
public class Counter extends Thread {
private Demo mDemo;
private int mAmount;
public Counter(Demo demo, int amount) {
// Remember the shared resource
mDemo = demo;
mAmount = amount;
}
#Override
public void run() {
for (int i < 0; i < mAmount; i++) {
// Call the count method provided
// by the shared resource
mDemo.count();
// Sleep some millis
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
This question already has answers here:
Notify not getting the thread out of wait state
(3 answers)
Closed 7 years ago.
Basically I have to create 3 classes (2 threaded).
First one holds some cargo (has a minimum capacity (0) and a maximum (200))
Second one supplies the cargo every 500ms.
Third one takes away from cargo every 500ms.
Main program has one cargo class(1), 2 supplier classes(2) and 2 substraction classes(3). Problem I'm having is that one by one, they're falling into a wait(); state and never get out. Eventually all of them get stucked in the wait() state, with the program running, but without them actually doing anything.
First class:
public class Storage {
private int maxCapacity;
private int currentCapacity;
public Storage( int currentCapacity, int maxCapacity ) {
this.currentCapacity = currentCapacity;
this.maxCapacity = maxCapacity;
}
public int getCapacity(){ return this.currentCapacity; }
public void increase( int q ) {
this.currentCapacity += q;
System.out.println("increase" + q + ". Total: " + currentCapacity);
}
public int getMax() { return this.maxCapacity; }
public void decrease( int q ) {
this.currentCapacity -= q;
System.out.println("decrease - " + q + ". Total: " + currentCapacity);
}
}
2nd class (supplier):
public class Supplier implements Runnable {
private int capacity;
private Storage storage;
private volatile boolean run;
public Supplier( int capacity, Storage storage ) {
this.capacity = capacity;
this.storage = storage;
this.run = true;
}
public void kiss_kill() { run = !run; }
public synchronized void add() {
while(storage.getCapacity() + capacity > storage.getMax()) {
try {
System.out.println("wait - supplier");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.increase(capacity);
notifyAll();
}
public void run() {
synchronized (this) {
while(run) {
add();
Thread.yield(); //would be wait(500), but this just speeds it up
}
}
}
}
3rd class (taker/demander):
public class Taker implements Runnable {
private int capacity;
private Storage storage;
private volatile boolean run;
public Taker( int capacity, Storage storage ) {
this.capacity = capacity;
this.storage = storage;
this.run = true;
}
public void kiss_kill() { run = !run; }
public synchronized void take() {
while(storage.getCapacity() - capacity < 0) {
try {
System.out.println("wait - taker");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.decrease(capacity);
notifyAll();
}
public void run() {
synchronized (this) {
while(run) {
take();
Thread.yield(); //again, wait(500) should be instead
}
}
}
}
Main is something like this:
public class Main{
public static void main(String... args) {
Storage sk = new Storage(100, 200);
Supplier[] s = { new Supplier(10, sk), new Supplier(15, sk) };
Taker[] p = { new Taker(15, sk), new Taker(20, sk) };
Thread t[] = {
new Thread(s[0]),
new Thread(s[1]),
new Thread(p[0]),
new Thread(p[1]) };
for(Thread th : t) th.start();
try {
Thread.sleep(60000); //program should last for 60s.
} catch (InterruptedException e) {
e.printStackTrace();
}
s[0].kiss_kill(); s[1].kiss_kill(); p[0].kiss_kill(); p[1].kiss_kill();
}
}
Why doesn't notifyAll() release the wait() state of other object? What could I do to fix this?
Sorry, I know it's a long example, I hate posting too many classes like this. Thanks for reading!
I translated the code, so if you spot anything that you're unsure about that I've missed, please tell me and I'll fix it right away!
Doing concurrency is easy:
Anyone can slap synchronized on methods and synchronized () {} around blocks of code. It does not mean it is correct. And then they can continue to slap synchronized on everything until it works until it doesn't.
Doing concurrency correctly is Hard:
You should lock on the data that needs to be consistent not the methods making the changes. And you have to use the same lock instance for everything.
In this case that is the currentCapacity in Storage. That is the only thing that is shared and the only thing that needs to be consistent.
What you are doing now is having the classes lock on instances of themselves which means nothing shared is being protected because there is no shared lock.
Think about it, if you are not locking on the same exact instance which must be final of an object then what are you protecting?
Also what about code that has access to the object that needs to be consistent and does not request a lock on it. Well it just does what it wants. synchronized() {} in calling classes is not how you protect shared data from external manipulation.
Thread safe objects are NOT about the synchronized keyword:
Read up on the java.util.concurrent package it has all the things you need already. Use the correct data structure for your use case.
In this particular case if you use AtomicInteger for your counter, you do not need any error prone manual locking, no need for synchronized anywhere, it is already thread safe.
Immutable Data:
If you work with immutable data exclusively you do not need any of this silly locking semantics that are extremely error prone for even those that understand it and even more so for those that think they understand it.
Here is a working idiomatic example:
This is a good chance to learn what non-deterministic means and how to use the step debugger in your IDE to debug concurrent programs.
Q33700412.java
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import com.vertigrated.FormattedRuntimeException;
public class Q33700412
{
public static void main(final String[] args)
{
final Storage s = new Storage(100);
final int ap = Runtime.getRuntime().availableProcessors();
final ExecutorService es = Executors.newFixedThreadPool(ap);
for (int i = 0; i < ap; i++)
{
es.execute(new Runnable()
{
final Random r = new Random();
#Override
public void run()
{
while (true)
{
/* this if/else block is NOT thread safe, I did this on purpose
the state can change between s.remainingCapacity() and
the call to s.increase/s.decrease.
This is ok, because the Storage object is internally consistent.
This thread might fail if this happens, this is the educational part.
*/
if (s.remainingCapacity() > 0)
{
if (r.nextBoolean()) { s.increase(r.nextInt(10)); }
else { s.decrease(10); }
System.out.format("Current Capacity is %d", s.getCurrentCapacity());
System.out.println();
}
else
{
System.out.format("Max Capacity %d Reached", s.getMaxCapacity());
System.out.println();
}
try { Thread.sleep(r.nextInt(5000)); }
catch (InterruptedException e) { throw new RuntimeException(e); }
}
}
});
}
es.shutdown();
try
{
Thread.sleep(TimeUnit.MINUTES.toMillis(1));
es.shutdown();
}
catch (InterruptedException e) { System.out.println("Done!"); }
}
public static final class Storage
{
/* AtomicInteger is used so that it can be mutable and final at the same time */
private final AtomicInteger currentCapacity;
private final int maxCapacity;
public Storage(final int maxCapacity) { this(0, maxCapacity); }
public Storage(final int currentCapacity, final int maxCapacity)
{
this.currentCapacity = new AtomicInteger(currentCapacity);
this.maxCapacity = maxCapacity;
}
public int remainingCapacity() { return this.maxCapacity - this.currentCapacity.get(); }
public int getCurrentCapacity() { return this.currentCapacity.get(); }
public void increase(final int q)
{
synchronized (this.currentCapacity)
{
if (this.currentCapacity.get() < this.maxCapacity)
{
this.currentCapacity.addAndGet(q);
}
else
{
throw new FormattedRuntimeException("Max Capacity %d Exceeded!", this.maxCapacity);
}
}
}
public int getMaxCapacity() { return this.maxCapacity; }
public void decrease(final int q)
{
synchronized (this.currentCapacity)
{
if (this.currentCapacity.get() - q >= 0)
{
this.currentCapacity.addAndGet(q * -1);
}
else
{
this.currentCapacity.set(0);
}
}
}
}
}
Notes:
Limit the scope of synchronized blocks to the minimum they need to protect and lock on the object that needs to stay consistent.
The lock object must be marked final or the reference can change and you will be locking on different instances.
The more final the more correct your programs are likely to be the first time.
Jarrod Roberson gave you the "how" half of the answer. Here's the other half--the "why".
Your Supplier object's add() method waits on itself (i.e., on the supplier object), and it notifies itself.
Your Taker object's take() method waits on its self (i.e., on the taker object), and it notifies its self.
The supplier never notifies the taker, and taker never notifies the supplier.
You should do all of your synchronization on the shared object (i.e., on the Storage object.
So I should convert storage into a thread?
No, you don't want Storage to be a thread, you want it to be the lock. Instead of having your Supplier objects and your Taker objects synchronize on themselves, they should all synchronize on the shared Storage object.
E.g., do this:
public void take() {
synchronized(storage) {
while(...) {
try {
storage.wait();
} catch ...
}
...
storage.notifyAll();
}
}
Instead of this:
public synchronized void take() {
while(...) {
try {
wait();
} catch ...
}
...
notifyAll();
}
And do the same for all of your other synchronized methods.
Just for practice I wanted to implement the java synchronized keyword as a java object.
Would you say the code below is a good design for this?
I guess AtomicReference would have a similar performance to AtomicBoolean?
Updated code after suggestions:
public class SynchronizedBlock implements Runnable{
private final Lock lock;
private final Runnable runnable;
public SynchronizedBlock(Runnable r, Lock l){
runnable = r;
lock = l;
}
public void run() {
try {
while(!lock.compareAndSet(false, true)){
Thread.sleep(100);
}
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Lock {
private final AtomicReference<Boolean> locked = new AtomicReference<Boolean>(false);
public boolean compareAndSet(boolean expected, boolean update){
return locked.compareAndSet(expected, update);
}
public boolean isLocked(){
return locked.get();
}
public void unlock(){
locked.set(false);
}
}
#Test
public void test() {
final SynchronizedBlock sb = new SynchronizedBlock(new Runnable(){
public void run() {
x++;
System.out.println(x);
}
}, new Lock());
Runnable r1 = new Runnable(){
int c = 0;
public void run() {
while(c<10){
sb.run();
c++;
}
}
};
Runnable r2 = new Runnable(){
int c = 0;
public void run() {
while(c<10){
sb.run();
c++;
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
while (t1.isAlive() && t2.isAlive()){
}
assertEquals(20,x);
}
You should add a method to encapsulate the compareAndSwap, and there is no point looping for the lock to be free before attempting to obtain it. Why get in the situation where you can see the lock is free but by the time you try to take it, it is gone.
I would remove the lock method and place the unlock in a finally lock so that an Exception/Error doesn't result in a lock which never unlocks.
Also I would use an AtomicBoolean which is more natural than an AtomicReference
Firstly and most importantly, you should remove Thread.sleep(100). This will cause at least 100ms latency even in only 2-thread contention.
You can simply use AtomicBoolean instead of AtomicReference to simplify your code. Also if you're really concerned about concurrency in high-contention situation, you can modify your code to check if it's locked before doing CAS.
while (true) {
if (lock.isLocked()) continue; // or get() == true if you use AtomicBoolean
if (lock.compareAndSet(false, true))
break;
}
This is an example of TTAS(Test-Test-And-Set) locking which takes advantage of local-spinning to reduce main-memory access while looping.
See http://en.wikipedia.org/wiki/Test_and_Test-and-set
In my class I have code like:
int counter1;
int counter2;
public void method1(){
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
}
public void method2() {
counter1=0;
counter2=0;
}
I need that both counters set together. I am afraid that OS can to method1 can be invoked after setting counter1 only. Does it possible?
Thanks.
Either use the synchronized keyword as the other answer suggest or use the ReentrantReadWriteLock if you have more reads than writes to the counter, for better performance. You can read about the lock here http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
private int counter1;
private int counter2;
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public void method1(){
r.lock();
try {
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
} finally { r.unlock(); }
}
public void method2() {
w.lock();
try {
counter1=0;
counter2=0;
} finally { w.unlock(); }
}
Sure, just use the synchronized keyword:
private final Object LOCK = new Object();
int counter1;
int counter2;
public void method1() {
synchronized(LOCK) {
if (counter1>0) {
...........do something
if (counter2>0) {
....do something else
}
}
}
public void method2() {
synchronized(LOCK) {
counter1=0;
counter2=0;
}
}
Some tips:
Use a private object for synchronization rather than marking a method synchronized. This prevents something external to you class from grabbing the lock and stalling things.
Make sure that you use the synchronized keyword everywhere, and make sure you always synchronize on the same object. If you forget to do either of those things, two processes can access the fields at the same time.
Beware of deadlocks. In a perfect world you'd write unit tests to ensure that locking is working the way you think it is.
Use a synchronized block or method to wrap access to the two counters, remember to use the same object to lock on.