Reputation: 49
I am trying to understand how locks and multithreading works before I move onto Conditions. This is the code I am testing currently:
public class tester {
private static int count = 0;
public void incrementCount() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new testing());
Thread thread2 = new Thread(new testing());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(count);
}
}
And this is the part that implements Runnable:
public class testing implements Runnable {
Lock lock = new ReentrantLock();
tester in = new tester();
public void run() {
for (int i = 0; i < 1000; i++) {
lock.lock();
in.incrementCount();
lock.unlock();
}
}
}
The problem that I am having is that I am trying to print out 2000 at the end of the main method, but it never actually gets to 2000 even though I am using locks. Help would be appreciated!
Upvotes: 1
Views: 112
Reputation: 719596
Thilo is correct, but I think it could be explained a different way.
The primary purpose of locks (both Lock
implementations and primitive locks) is to gain exclusive access to some data. The "protocol" is:
The assumption is that while one thread holds the lock, no other thread can access the data1.
But this only works if there is a one-to-one association between the lock and the data. That is, you need to obtain the lock for the data in order to gain exclusive access. If you acquire the lock for a different group of data, it won't work. It also typically2 won't work if you try to use more than one lock for the same group of data.
In your example, each thread has its own lock, but there is just one data that they are trying to control access to. As a result, the two thread can access and update the data at the same time.
Thilo's answer shows (one) correct way to solve the problem.
1 - This is actually a "contract" between the threads. The Java language does not (and cannot) prevent a thread from accessing and updating the "controlled" data without holding the lock. The threads have to obey the contract to achieve proper synchronization and mutual exclusion.
2 - Typically, but not always. For example, ReadWriteLock
provides a pair of lock objects that together provide either exclusive read-write access, or shared read-only access.
Upvotes: 2
Reputation: 262834
even though I am using locks.
You are using a separate lock for each of your two threads.
If you want the lock to coordinate between the threads, they both need to work with the same lock instance. Otherwise it is quite pointless.
Change to something like
class Testing implements Runnable {
private final Lock lock;
// pass in the lock to use via the constructor
// both threads need to receive the same lock
Testing(Lock lock){ this.lock = lock; }
public void run() {
for (int i = 0; i < 1000; i++) {
lock.lock();
Tester.incrementCount();
lock.unlock();
}
}
}
Upvotes: 2