suppose we have these classes:
public class Record {
int key;
int value;
Record(){
this.key=0;
this.value=0;
}
Record(int key,int value){
this.key=key;
this.value=value;
}
public class Table {
static final Record[] table = new Record [100];
static final Object[] locks = new Object[table.length];
static{
for(int i = 0; i < table.length; i++) {
locks[i] = new Object();
}
table[0]=new Record(0,0);
table[1]=new Record(1,10);
table[2]=new Record(2,20);
table[3]=new Record(3,30);
}
}
And i want to implement in TRansaction class these method
void setValueByID(int key, int value)
The key-value pair (record) is locked(it cannot be read/written from other transactions) until the setValueByID method finishes.
int getValueByID(int key)
The key-value pair (record) is locked until the transaction commits
void commit()
it unlocks all the key-value pairs (records) locked in the current transaction
So, my implementation is :
class Transaction extends Thread {
//there is no problem here
public void setValueByID(int key, int value){
synchronized(Table.locks[key]) {
Table.table[key].key=key;
}
}
//the problem is here...
//how can i make other thread wait until current thread calls Commit()
public int getValueByID(int key){
int value=0;
synchronized(Table.locks[key]){
value= Table.table[key].key;
}
return value;
}
void commit(){
}
Ahmad
You cannot use synchronized blocks to achieve it, instead you will need to use something like locks.
public Main {
public static void main(String[] args) {
final Transaction T = new Transaction();
for (int n = 0; n < 10; n++) {
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 1000; i++) {
T.setValueByID(i % 100, i);
T.getValueByID(i % 100);
if (i % 20 == 0) T.commit();
}
}
}).start();
}
}
}
class Table {
static final Record[] table = new Record[100];
static final ReentrantLock[] locks = new ReentrantLock[table.length];
static {
for (int i = 0; i < table.length; i++) {
locks[i] = new ReentrantLock();
}
table[0] = new Record(0, 0);
table[1] = new Record(1, 10);
table[2] = new Record(2, 20);
table[3] = new Record(3, 30);
}
}
class Transaction {
private ThreadLocal<Set<ReentrantLock>> locks = new ThreadLocal<Set<ReentrantLock>>() {
#Override
protected Set<ReentrantLock> initialValue() {
return new HashSet<ReentrantLock>();
}
};
private void attainLock(int key) {
final ReentrantLock lock = Table.locks[key];
lock.lock();
locks.get().add(lock);
}
private void releaseLock(int key) {
final ReentrantLock lock = Table.locks[key];
releaseLock(lock);
}
private void releaseLock(ReentrantLock lock) {
final Set<ReentrantLock> lockSet = locks.get();
if (!lockSet.contains(lock)) {
throw new IllegalStateException("");
}
lockSet.remove(lock);
lock.unlock();
}
private void releaseLocks() {
final Set<ReentrantLock> lockSet = new HashSet<ReentrantLock>(locks.get());
for (ReentrantLock reentrantLock : lockSet) {
releaseLock(reentrantLock);
}
}
public void setValueByID(int key, int value) {
attainLock(key);
Table.table[key].key = key;
releaseLock(key);
}
public int getValueByID(int key) {
attainLock(key);
return Table.table[key].key;
}
void commit() {
releaseLocks();
}
}
The problem with locks is that during your transaction, if you do not follow an order while attaining the locks, you can run into deadlocks! Also, you need to ensure you handle exceptions properly and always release the locks by calling commit().
This sort of synchronization is achieved using the wait()/notify() methods with some sort of lock. Read the Java tutorial on them (and other synchronization concepts) here.
Ideally you need to become familiar with the ReadWriteLock of java concurrent package. setValueId should obtain a write lock and hold it until transaction commits. getValueId only needs a read lock that can be shared by other read locks and be released when the method ends.
Also take into account some timeout so that the locks are not held indefinitely.
Research for:
read/write lock pattern
isolation levels in database systems
transaction handling
Related
I have a problem where there is a BoundedBuffer and there are Consumers and Producers, the producers fill the buffer and consumers remove from the buffer.
I'm using threads for the Consumers and Producers, and i was trying to use lock conditions to ensure that the buffer isn't full to the producer and isn't empty for the consumer.
Unfortunately it's not working the way I wanted, it seems that the Consumer/Producer, when they are in Condition.await, don't let the other threads work. Shouldn't they let them?
Here is my code
class main
{
public static void main (String[] args) throws InterruptedException
{
final int N = Integer.parseInt(args[0]);
BoundedBuffer teste = new BoundedBuffer(N);
Thread c = new Consumidor(teste,N);
Thread p = new Produtor(teste,N);
c.start();
p.start();
c.join();
p.join();
}
}
class BoundedBuffer
{
ArrayList<Integer> array;
int index;
int size;
Lock l = new ReentrantLock();
Condition notFull = l.newCondition();
Condition notEmpty = l.newCondition();
BoundedBuffer(int N)
{
this.array=new ArrayList<Integer>(N);
this.index = 0;
this.size=N;
}
public synchronized void put(int e) throws InterruptedException
{
l.lock();
try
{
while(this.index >= this.size)
{
notFull.await();
}
this.array.add(index,e);
this.index++;
notEmpty.signal();
}
finally
{
l.unlock();
}
}
public synchronized int get() throws InterruptedException
{
int i;
l.lock();
try
{
while(this.index <=0)
{
notEmpty.await();
}
this.index--;
notFull.signal();
i = this.array.get(index);
}
finally
{
l.unlock();
}
return i;
}
}
class Consumidor extends Thread
{
private BoundedBuffer b;
final int j;
public Consumidor(BoundedBuffer b, int j)
{
this.b = b;
this.j=j;
}
public void run()
{
int a;
for (int i = 0; i < j ;++i)
{
try
{
a=b.get();
System.out.println("GET: " +a);
}
catch (Exception e) {}
}
}
}
class Produtor extends Thread
{
private BoundedBuffer b;
final int j;
public Produtor(BoundedBuffer b, int j)
{
this.b = b;
this.j=j;
}
public void run()
{
int a;
for (int i = 0; i < j; ++i)
{
try
{
b.put(i);
System.out.println("PUT: " +i);
}
catch (Exception e) {}
}
}
}
Thanks in advance
Don’t mix intrinsic locks (meaning synchronized) with reentrantLocks. This code is trying to acquire the intrinsic lock and then the reentrantlock.
Putting synchronized on an instance method requires the thread calling the method to acquire the intrinsic lock on the instance. ReentrantLock is a separate locking construct that does not use that keyword. Mixing the two mechanisms is unnecessary and can only cause trouble.
(Specifically the code is calling await on the condition object, which causes the thread to release the reentrant lock, but the thread keeps holding onto the intrinsic lock, preventing the other thread from entering a synchronized method.)
The fix for this is to delete the synchronized keyword from your code.
Now I'm struggling with the task from the title. I create X threads, each of them prints Y equal digits (getting from constructor, for example "11111", "222222" etc) for Z times in cycle. So the result looks like:
111111111
222222222
333333333
111111111
222222222
333333333
for X = 3, Y = 9 and Z = 2.
Firstly I've solved this issue using sleep, interrupt and passing "next" thread to the constructor of previous one. One interrupts another etc. Next step is to get the same output using wait/notify instead sleep and interrupt. As far as I can see, it's neccesary to create the shared monitor object, to invoke wait after every printing and in a some moment " I should invoke notifyAll.
Current code is:
public class PrinterController {
private static final int THREADS_NUMBER = 5;
public static void main(String[] args) {
Printer[] printers = new Printer[THREADS_NUMBER];
for (int i = 0; i < THREADS_NUMBER; i++) {
printers[i] = new Printer(i);
printers[i].start();
}
}
}
public class Printer extends Thread {
private static int portion = 10;
private static int totalNumber = 100;
private int digit;
private static final Object monitor = new Object();
public Printer(int digit) {
this.digit = digit;
}
#Override
public void run() {
synchronized (monitor) {
int portionsNumber = totalNumber / portion;
for (int i = 0; i < portionsNumber; i++) {
printLine();
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private void printLine() {
for (int j = 0; j < portion; j++) {
System.out.print(digit);
}
System.out.println();
}
}
Could you help to improve it? I found similar tasks but they don't contain appropriate answers. Thanks.
Final solution based on the Nadir's answer:
public class Printer extends Thread {
private static int portion = 10;
private static int totalNumber = 100;
private int digit;
static Object monitor = new Object();
static Integer counter = 0;
public Printer(int digit) {
this.digit = digit;
}
#Override
public void run() {
int portionsNumber = totalNumber / portion;
for (int i = 0; i < portionsNumber; i++) {
synchronized (monitor) {
while (digit != counter) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
printLine();
monitor.notifyAll();
}
}
}
private void printLine() {
for (int j = 0; j < portion; j++) {
System.out.print(digit);
}
System.out.println();
counter = (counter + 1) % PrinterController.THREADS_NUMBER;
}
}
It can be accomplished with a class used to synchronize the threads (and even make sure they are orderer). All threads would share the same instance.
public class Synchronizer
{
private int nextThread;
private int maxNumThreads;
public Synchronizer(int numThreads)
{
maxNumThreads = numThreads;
nextThread = 0;
}
public void doSync(int threadId) throws Exception
{
synchronized(this)
{
while(nextThread != threadId)
{
wait();
}
}
}
public void threadDone(int threadId) throws Exception
{
synchronized(this)
{
nextThread = (threadId + 1) % maxNumThreads;
notifyAll();
}
}
}
On your thread's run(), you would call doSync() before printing anything. Then you would put the code for printing, and afterwards, you would call threadDone(), allowing the next thread to be released. The id is used to enforce an order.
Im trying to make 2 threads that read/write to a counter using thread safe methods.
I have written some code to try test this but the read thread just reads the counter at its max (1000)
Main:
public static void main(String[] args) {
Counter c = new Counter();
Thread inc = new Increment(c);
Thread read = new Read(c);
inc.start();
read.start();
}
Counter:
public class Counter {
private int count;
public Counter() {
count = 0;
}
public synchronized void increment() {
count++;
}
public synchronized int getVal() {
return count;
}
}
Increment:
public class Increment extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Increment(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
myCounter.increment();
}
}
}
Read:
public class Read extends Thread {
private static final int MAX = 1000;
private Counter myCounter;
public Read(Counter c) {
myCounter = c;
}
public void run() {
for (int i = 0; i < MAX; i++) {
System.out.println(myCounter.getVal());
}
}
}
Would I be better off using Atomic Integer to hold the value of the counter to allow me to safely increment it and get the value?
Your code is perfectly fine as is. It just so happened that your increment thread finished all its increments before the read thread got a chance to read. 1,000 increments takes almost no time at all.
If you want interleave execution of Read thread and Increment thread much more often then the natural operating system thread pre-emption, just make each thread give up their lock (by calling <lockedObject>.wait() followed by <lockedObject>.notify() or notifyAll() in the respective run() methods:
[In Reader]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
System.out.println(myCounter.getVal());
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
[In Increment]:
public void run() {
for (int i = 0; i < MAX; i++) {
synchronized (myCounter) {
myCounter.increment();
try {
myCounter.wait(0L, 1);
myCounter.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Upping the MAX constant to 1_000_000_000 (1 billion) made the treads interleave as well every now and then (on my machine interleave happened just by gazing at few printouts between 150 and 400_000 iterations).
This question already has answers here:
synchronized block for an Integer object
(3 answers)
Closed 6 years ago.
Edit:
I have already found the answer on the stack:
https://stackoverflow.com/a/16280842/3319557
I face a problem with synchronization. I have two following methods:
public synchronized void incrementCounter1() {
counter++;
}
public void incrementCounter2() {
synchronized (counter) {
counter++;
}
}
I test each of those (separately) in many threads. First method behaves as expected, but second (incrementCounter2) is wrong. Can somebody explain why is this happening?
I assume this method is well designed, as I found something lookalike in Java Concurrency in Practice. Snipped from this book:
#ThreadSafe
public class ListHelper<E> {
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
...
public boolean putIfAbsent(E x) {
synchronized (list) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
}
}
I use monitor from the Object I am modifying, exactly like in book.
Full code here:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SynchronizationTest {
public static final int N_THREADS = 500;
public static final int N_Loops = 5000;
private Integer counter = 0;
Lock l = new ReentrantLock();
public void incrementCounter0() {
counter++;
}
public synchronized void incrementCounter1() {
counter++;
}
public void incrementCounter2() {
synchronized (counter) {
counter++;
}
}
public void incrementCounter3() {
try {
l.lock();
counter++;
} finally {
l.unlock();
}
}
private interface IncrementStrategy {
void use(SynchronizationTest t);
}
private static class IncrementingRunnable implements Runnable {
SynchronizationTest synchronizationTest;
IncrementStrategy methodToUse;
public IncrementingRunnable(SynchronizationTest synchronizationTest, IncrementStrategy methodToUse) {
this.synchronizationTest = synchronizationTest;
this.methodToUse = methodToUse;
}
#Override
public void run() {
for (int i = 0; i < N_Loops; i++) {
methodToUse.use(synchronizationTest);
}
}
}
public void test(IncrementStrategy methodToUse, String methodName) {
counter = 0;
Thread[] threads = new Thread[N_THREADS];
for (int i = 0; i < N_THREADS; i++) {
threads[i] = new Thread(new IncrementingRunnable(this, methodToUse));
threads[i].start();
}
for (int i = 0; i < N_THREADS; i++) {
try {
threads[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(methodName + " diff than expected " + (counter - N_THREADS * N_Loops));
}
public void test() {
test(t -> t.incrementCounter0(), "incrementCounter0 (expected to be wrong)");
test(t -> t.incrementCounter1(), "incrementCounter1");
test(t -> t.incrementCounter2(), "incrementCounter2");
test(t -> t.incrementCounter3(), "incrementCounter3");
}
public static void main(String[] args) {
new SynchronizationTest().test();
}
}
I know, that ExecutorService should be used, whole problem can be solved with AtomicLong, but it is not the point of this question.
Output of the code is:
incrementCounter0 (expected to be wrong) diff than expected -1831489
incrementCounter1 diff than expected 0
incrementCounter2 diff than expected -599314
incrementCounter3 diff than expected 0
PS.
If I add the field to SynchronizationTest
Object counterLock = new Object();
and change
incrementCounter2 to:
public void incrementCounter2() {
synchronized (counterLock) {
counter++;
}
}
Then incremetCounter2 works as expected.
You're synchronizing on different objects
incrementCounter1 synchronizes on this, while incrementCounter2 synchronizes on the counter Integer object itself.
You are trying to use two lock monitors (assuming counter is an Object, perhaps Integer?)
public class Foo {
// Uses instance of Foo ("this")
public synchronized void incrementCounter1() {
counter++;
}
public void incrementCounter2() {
// uses counter object as lock monitor
synchronized (counter) {
counter++;
}
}
}
I am not sure what you are trying to achieve with counter++ as it seems counter is of type Integer?
Few options to fix your problem:
Use a the same lock monitor
You might want to look into AtomicInteger
Use the lock API (e.g., ReentrantReadWriteLock)
Hideous.
synchronized void method(...
Synchronizes on the this Object.
synchronized(object) {
...
Synchronizes on object.
Now:
synchronized (counter) {
++counter;
must also synchronize on an Object, but counter is a primitive type, an int.
What happens, is that counter is boxed in an Integer.
When counter is 0 .. 127 the Integer object retrieved is everytime different, but shared. For say 1234 a new unique Integer object is created, and synchronized has no effect whatsoever. (Integer being immutable.)
I would call this almost a language error, something for FindBugs to find.
Generally, as java developers all know that we must use "synchronized" to control the method execution one by one, but I see the following code choose static variable to control, and i can't simulate the condition to demonstrate that the method is error, how do I modify the code to output the value more than 1000?
public class ThreadJunk implements Runnable{
private Info info;
public ThreadJunk(Info info) {
this.info = info;
}
public static void main(String args[]) throws Exception {
for(int j=0;j<100;j++) {
Info ii = new Info();
for(int i=0;i<1000;i++) {
Thread t = new Thread(new ThreadJunk(ii));
t.start();
}
System.out.println(ii.getValue());
}
}
#Override
public void run() {
info.addValue();
}
}
class Info {
public static boolean IS_LOCKED = false;
private int value = 0;
public void addValue() {
if(IS_LOCKED)
return;
IS_LOCKED = true;
value++;
IS_LOCKED = false;
}
public int getValue() {
return value;
}
}
In my computer, I have never get the result that more than 1000
Look at this part of your code:
Info ii = new Info();
for (int i = 0; i < 1000; i++) {
Thread t = new Thread(new ThreadJunk(ii));
t.start();
}
For every Info object you are creating no more than 1000 threads. You should not expect the value field to get incremented more than 1000 times.
Info object has value as member variable.And one Info object is shared in 999 threads as per your thread creation logic.
for(int j=0;j<100;j++) {
Info ii = new Info();
for(int i=0;i<1000;i++) {
Thread t = new Thread(new ThreadJunk(ii));
t.start();
}
System.out.println(ii.getValue());
}
Hence obviously following would be never greater than 1000.
System.out.println(ii.getValue())