I implemented a simple locking solution that creates a lock for a value rather than object and want to know the experts' opinion for possible performance or security drawbacks.
The idea is to use it for account balance update acquiring the lock for unique account number.
Here is an implementation:
import java.util.*;
public class Mutex<T> {
private final Set<T> set = new HashSet();
public synchronized Lock acquireLock(
T value
) throws InterruptedException {
while(!set.add(value)) {
this.wait();
}
return new Lock(value);
}
public class Lock {
private final T value;
public Lock(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void release() {
synchronized(Mutex.this) {
set.remove(value);
Mutex.this.notifyAll();
}
}
}
}
And here is a sample usage to check the operability:
public class Test {
private Mutex mutex = new Mutex();
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(() -> {
try {
test.test("SameValue");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
t1.setName("Thread 1");
Thread t2 = new Thread(() -> {
try {
test.test("SameValue");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
t2.setName("Thread 2");
t1.start();
t2.start();
}
public void test(String value)
throws
InterruptedException {
Lock lock = mutex.acquireLock(value);
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName());
} finally {
lock.release();
}
}
}
Regarding your implementation,
I would have use a Set instead of a List to hold your values (I assume the values have proper equals/hashcode for this to make sense): the List#contains method is in O(n) which might be expensive if you have a lot of IBAN used at the same time.
Also, you should avoid using synchronize(this) (which is the same as the synchronized keyword on method).
To solve your problem, I use something like this:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Locks<T> {
private final Lock lock = new ReentrantLock();
//a Bimap from guava might be better here if you have the dependency
//in your project
private final Map<Reference<?>, T> valuePerReference = new HashMap<>();
private final Map<T, Reference<Lock>> locks = new HashMap<>();
private final ReferenceQueue<Lock> lockReferenceQueue = new ReferenceQueue<>();
public Locks() {
final Thread cleanerThread = new Thread(new Cleaner());
cleanerThread.setDaemon(true);
cleanerThread.start();
}
/**
* #param value the value the synchronization must be made on
* #return a lock that can be used to synchronize block of code.
*/
public Lock getLock(T value) {
lock.lock();
try {
return getExistingLock(value).orElseGet(() -> createNewLock(value));
} finally {
lock.unlock();
}
}
private Optional<Lock> getExistingLock(T value) {
return Optional.ofNullable(locks.get(value)).map(Reference::get);
}
private Lock createNewLock(T value) {
//I create ReentrantLock here but a Supplier<Lock> could be a parameter of this
//class to make it more generic. Same remark for SoftReference below.
final Lock lock = new ReentrantLock();
final Reference<Lock> reference = new SoftReference<>(lock, lockReferenceQueue);
this.locks.put(value,reference);
this.valuePerReference.put(reference,value);
return lock;
}
private void removeLock(Reference<?> reference) {
lock.lock();
try {
final T value = valuePerReference.remove(reference);
locks.remove(value);
} finally {
lock.unlock();
}
}
private class Cleaner implements Runnable {
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
final Reference<? extends Lock> garbaged = lockReferenceQueue.remove();
removeLock(garbaged);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}
I then use this like this:
import java.util.concurrent.locks.Lock;
public class Usage {
private final Locks<String> locks = new Locks<>();
public void doSomethind(String iban) {
final Lock lock = locks.getLock(iban);
lock.lock();
try {
//.. do something with your iban
} finally {
lock.unlock();
}
}
}
Although it uses ReentrantLock, the code can be easily modified for ReadWriteLock for instance.
Related
Need help with code at below link as it should run indefinitely likewise with any typical producer/consumer problem but somehow it is getting stuck on call of condition.signal(). What am I doing wrong here?
In main method, I have created two thread, one is consumer and other one is producer. it has shared task queue where both updates the entry.
package com.anurgup.handson;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionService implements Runnable {
Lock lock = new ReentrantLock();
Condition added = lock.newCondition();
Condition removed = lock.newCondition();
// type of service
String type;
// shared task for insertion and deletion of task
static Queue<Integer> task = new PriorityQueue<Integer>();
// max number of task allowed
private static final int MAX_SIZE = 5;
public ConditionService(String type) {
this.type = type;
}
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(2);
service.submit(new ConditionService("producer"));
service.submit(new ConditionService("consumer"));
}
public void produce() {
try {
while (true) {
System.out.println("in producer...");
synchronized (task) {
while (task.size() == MAX_SIZE)
removed.await();
System.out.println("added item: " + task.size());
task.add(task.size());
added.signal();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void consume() {
try {
while (true) {
System.out.println("in consumer...");
synchronized (task) {
while (task.isEmpty())
added.await();
System.out.println("removed item: " + task.peek());
task.remove();
removed.signal();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void run() {
if (this.type.equals("producer"))
this.produce();
else
this.consume();
}
}
You're making two mistakes. First, your lock and conditions need to be static, or each task will only synchronize and wait on itself. Second, you need to use lock.lock(), not synchronized. It should look like this:
lock.lock();
try {
// wait
// produce/consume
} finally {
lock.unlock();
}
I have two classes each with one method.
class A {
private void insert(String usedId){
// ...
}
}
class B {
private void refresh(String userId){
// ...
}
}
Each method is called from a different Thread. They are called from different Threads for different userIds.
I need to lock the first method when second is called and vise versa for the same userId.
Is the best choice to hold a List of ids and set the lock?
We introduce a LockDispenser. You pass this object to all As and Bs you want to have thread safe. It will provide Lock objects with createLock(String forId) which need to be released after use by calling releaseLock(String forId).
public class LockDispenser {
private final Map<String, Lock> dispenser = new LinkedHashMap<>();
public Object createLock(String forId) {
synchronized (dispenser) {
if (!dispenser.containsKey(forId)) {
dispenser.put(forId, new Lock());
}
Lock lock = dispenser.get(forId);
lock.referenceCounter++;
return lock;
}
}
public void releaseLock(String forId) {
synchronized (dispenser) {
Lock lock = dispenser.get(forId);
lock.referenceCounter--;
if (lock.referenceCounter == 0) {
dispenser.remove(forId);
}
}
}
public static class Lock {
private int referenceCounter = 0;
}
}
Now the actual thread safety comes from using the Lock in a synchronized block.
public class A {
private LockDispenser dispenser;
public A(LockDispenser dispenser) {
this.dispenser = dispenser;
}
private void insert(String userId) {
synchronized (dispenser.createLock(userId)) {
// code
}
dispenser.releaseLock(userId); // consider putting this in a finally block
}
}
public class B {
private LockDispenser dispenser;
public B(LockDispenser dispenser) {
this.dispenser = dispenser;
}
private void refresh(String userId) {
synchronized (dispenser.createLock(userId)) {
// code
}
dispenser.releaseLock(userId); // consider putting this in a finally block
}
}
Make sure releaseLock(String forId) is called even if an Exception is thrown. You can do this by putting it into a finally block.
And create them like such:
public static void main(String... args) {
LockDispenser fooLock = new LockDispenser();
A fooA = new A(fooLock);
B fooB = new B(fooLock);
LockDispenser barLock = new LockDispenser();
A barA = new A(barLock);
B barB = new B(barLock);
}
fooA and fooB are thread safe with each other and so are barA and barB.
I am trying to create a basic Semaphore implementation using Queue. The idea is, there is a database, and there are 10 writers. Writers can only write to the database in mutual exclusion. I am using Queue because I want to implement First In First Out and Last In First Out.
Using Semaphore, I can't notify a specific thread to wake up. So my idea is what I am doing is for every Writer, I create an object and tell the Writer to wait on that object. Puts that object in a queue. Then remove the object from the queue and notify the Thread that is waiting on that object. In this way, I think I can make a FIFO or LIFO implementation.
I need help on the actual code implementation:
1. I run the code below, it gave me a lot of IllegalMonitorStateException.
2. FIFO and LIFO code (my FIFO code seems incorrect, while for LIFO code, I'm thinking to use Stack instead of Queue).
public class Test {
public static void main(String [] args) {
Database db = new Database();
for (int i = 0; i < 10; i++)
(new Thread(new Writer(db))).start();
}
}
public class Writer implements Runnable {
private Database database;
public Writer(Database database) {
this.database = database;
}
public void run() {
this.database.acquireWriteLock();
this.database.write();
this.database.releaseWriteLock();
}
}
public class Database {
private Semaphore lockQueue;
public Database() {
this.lockQueue = new Semaphore();
}
public void write() {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {}
}
public void acquireWriteLock() {
lockQueue.acquire();
}
public void releaseWriteLock() {
lockQueue.release();
}
}
import java.util.Queue;
import java.util.LinkedList;
public class Semaphore {
private Queue<Object> queue;
public Semaphore() {
this.queue = new LinkedList<Object>();
}
public synchronized void acquire() {
Object object = new Object();
try {
if (this.queue.size() > 0) {
object.wait();
this.queue.add(object);
}
} catch (InterruptedException ie) {}
this.queue.add(object);
}
public synchronized void release() {
Object object = this.queue.remove();
object.notify();
}
}
You need to acquire the lock of the object before you can use wait() and notify().
Try to check if the following code will work:
public class Semaphore {
private Queue<Object> queue;
private int state;
public Semaphore() {
this.queue = new LinkedList<Object>();
}
public void acquire() {
Object object = new Object();
synchronized (object) {
try {
if (this.state > 0) {
this.queue.add(object);
object.wait();
} else {
state++;
}
} catch (InterruptedException ie) {
}
}
}
public void release() {
Object object = this.queue.poll();
state--;
if(null == object) {
return;
}
synchronized (object) {
object.notify();
}
}
}
I am using executor framework for carrying out a large task. I need to keep a count of how many have been completed for process status purpose. So i have created a singleton class with a counter to keep the count.
public class ProgramInitializationTracker {
private static Map<String, Integer> programInitializedTracker = new HashMap<>();
private static ProgramInitializationTracker instance;
private ProgramInitializationTracker(){
}
public static ProgramInitializationTracker getInstance(){
if(instance == null){
synchronized (ProgramInitializationTracker.class) {
if(instance == null){
instance = new ProgramInitializationTracker();
}
}
}
return instance;
}
public Integer getProgramInitializedTracker(String key) {
return programInitializedTracker.get(key);
}
public void setProgramInitializedTracker(String key, int value) {
synchronized (ProgramInitializationTracker.class) {
ProgramInitializationTracker.programInitializedTracker.put(key, value);
}
}
}
But the problem is only by synchronizing set method will not really ensure that i have correct value of count. As far as i could get multithreading. Do making get function also synchronized will help me. If no then what should i have done to make it correct.
You should not attempt to implement your own thread-safe access to a collection when Java already provides this for you.
You should use a ConcurrentHashMap. Reads such as get do not block.
But rather than use an Integer type as the value stored in the map, you should use an AtomicInteger, which will ensure that multiple threads attempting to modify the value associated with the same key will be thread safe.
Under constraints you posted, simply sharing an instance of AtomicInteger between tasks you submit to an ExecutorService and a place you want to have a metric must do. variant1 is for having single counter covering all tasks and variant2 is for having counter per task type. This code is (should be) thread-safe.
#ThreadSafe
class Test {
private static class CountingRunnable implements Runnable {
#Nonnull
private final Runnable actualTask;
#Nonnull
private final AtomicInteger submitted;
public CountingRunnable(#Nonnull Runnable actualTask, #Nonnull AtomicInteger submitted) {
this.actualTask = actualTask;
this.submitted = submitted;
}
#Override
public void run() {
actualTask.run();
submitted.incrementAndGet();
}
}
public static void main(String[] args) throws InterruptedException {
variant2();
}
private static void variant1() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(2);
AtomicInteger counter = new AtomicInteger();
final CountDownLatch latch = new CountDownLatch(1);
service.submit(new CountingRunnable(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
latch.countDown();
} catch (InterruptedException e) {}
}
}, counter));
latch.await();
System.out.println(counter.get());
service.shutdown();
}
private enum TaskType {
TYPE_1,
TYPE_2
}
private static void variant2() throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(2);
final CountDownLatch latch = new CountDownLatch(2);
final EnumMap<TaskType, AtomicInteger> metrics = new EnumMap<>(TaskType.class);
metrics.put(TaskType.TYPE_1, new AtomicInteger());
metrics.put(TaskType.TYPE_2, new AtomicInteger());
service.submit(new CountingRunnable(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, metrics.get(TaskType.TYPE_1)));
service.submit(new CountingRunnable(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, metrics.get(TaskType.TYPE_2)));
latch.await();
System.out.println("type 1: " + metrics.get(TaskType.TYPE_1));
System.out.println("type 2: " + metrics.get(TaskType.TYPE_2));
service.shutdown();
}
}
I have that code:
Main class:
public class myTest {
public static void main(String[] args) {
try {
Thread t1 = new myThreadClass("thread 1");
t1.start();
} catch (UnknownHostException ex) {
Logger.getLogger(glownyTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(glownyTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
My Thread class
public class myThreadClass extends Thread {
private HashSet<String> texts = new HashSet<String>();
public myThreadClass(String id) throws UnknownHostException, IOException {}
#Override
public void run() {
... collecting Strings into my hashSet ....
}
public HashSet<String> getTexts() {
return texts;
}
}
My Thread class is watching for network traffic, so I just cant call once
t1.getTexts()
whenever I want, because my hashSet can be empty (there are delays and latency in this network). How can I watch this texts hashSet and when some String will be added into hashSet - I i want my MAIN CLASS know about it? I just want to watch my Thread resources from Main class in smart way :)
If it will still be empty after my thread timeout, I want to know about it too.
You can use condition variables for this. Try something like:
class Monitor {
private final ConcurrentMap<String,String> data = new ConcurrentHashMap<String,String>();
private final Object mutex = new Object();
/* Private to the monitoring thread. Wakes up other
* threads, which may be waiting for data to arrive
*/
public void addElement(String key) {
data.put(key, key);
synchronized (mutex) { mutex.notifyAll(); }
}
public void removeElement(String key) {
data.remove(key);
synchronized (mutex) { mutex.notifyAll(); }
}
public Set<String> getElements() {
return data.keySet();
}
/* Can be called from any thread. Will wait at most "timeout"
* milliseconds
*/
public boolean waitForChanges(long timeout) throws InterruptedException {
final long then = System.currentTimeMillis() + timeout;
long left = timeout;
synchronized (mutex) {
while (data.isEmpty() && left > 0) {
mutex.wait(left);
left = then - System.currentTimeMillis();
}
return !data.isEmpty();
}
}
}
class MonitoringTask extends Runnable {
private final Monitor monitor;
MonitoringTask(Monitor m) {
this.monitor = m;
}
public void run() {
while (true) {
if (somethingHasHappened()) {
monitor.addElement("foo");
}
}
}
}
class Main {
public static void main(String[] args) {
final Monitor monitor = new Monitor();
final MonitoringTask task = new MonitoringTask(monitor);
final Thread thread = new Thread(task);
thread.setName("Monitor Thread");
thread.start();
if (monitor.waitForChanges(1500)) {
final Set<String> elts = monitor.getElements();
...
} else {
// Time-out
}
}
}
(I haven't tried to present this to a Java compiler, so watch out for all kinds of mistakes).