I use Java 8. I have an event handler that accepts events with a high rate, (n per second) and I want to flush them out to storage when I get so many of them (in this simplified example 1000)
Do I have a visibility error on line 25 myCache.get(event.getKey()).add(event.getBean()); ?
Should I synchronize on handleEvent() method?
public class myClass extends MySimpleEventHanlder {
private Map<String, List<MyBean>> myCache;
private ScheduledExecutorService scheduler;
public void MyClass() {
myCache = new ConcurrentHashMap<String, List<MyBean>>();
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
for (Iterator<Map.Entry<String, List<MyBean>>> it = myCache.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, List<MyBean>> entry = it.next();
if (entry.getValue().size() >= 1000) {
it.remove();
//do some more processing , flush to storage
}
}
}, 0, 60, TimeUnit.SECONDS);
}
#Override
public void handleEvent(Event event) {
if (myCachetCache.containsKey(event.getKey())) {
myCache.get(event.getKey()).add(event.getBean());
}
else{
List<MyBean> beans = new ArrayList<MyBeans>();
beans.add(event.getBean());
myCache.put(event.key, beans);
}
}
}
You definitely have visibility problems: you add items into an ArrayList in one thread, and read the size() from that ArrayList in another thread, with no synchronization in between.
Another problem is that the key may get removed between the calls to myCache.containsKey and myCache.get. This would cause a NullPointerException. That could be solved by using compute, which is guaranteed to be atomic.
myCache.compute(event.getKey(), (key, value) -> {
if (value == null) {
value = new ArrayList<>();
}
value.add(event.getBean());
return value;
});
Related
Within ConcurrentHashMap.compute() I increment and decrement some long value located in shared memory. Read, increment/decrement only gets performed within compute method on the same key.
So the access to long value is synchronised by locking on ConcurrentHashMap segment, thus increment/decrement is atomic. My question is: Does this synchronisation on a map guarantee visibility for long value? Can I rely on Map's internal synchronisation or should I make my long value volatile?
I know that when you explicitly synchronise on a lock, visibility is guaranteed. But I do not have perfect understanding of ConcurrentHashMap internals. Or maybe I can trust it today but tomorrow ConcurrentHashMap's internals may somehow change: exclusive access will be preserved, but visibility will disappear... and it is an argument to make my long value volatile.
Below I will post a simplified example. According to the test there is no race condition today. But can I trust this code long-term without volatile for long value?
class LongHolder {
private final ConcurrentMap<Object, Object> syncMap = new ConcurrentHashMap<>();
private long value = 0;
public void increment() {
syncMap.compute("1", (k, v) -> {
if (++value == 2000000) {
System.out.println("Expected final state. If this gets printed, this simple test did not detect visibility problem");
}
return null;
});
}
}
class IncrementRunnable implements Runnable {
private final LongHolder longHolder;
IncrementRunnable(LongHolder longHolder) {
this.longHolder = longHolder;
}
#Override
public void run() {
for (int i = 0; i < 1000000; i++) {
longHolder.increment();
}
}
}
public class ConcurrentMapExample {
public static void main(String[] args) throws InterruptedException {
LongHolder longholder = new LongHolder();
Thread t1 = new Thread(new IncrementRunnable(longholder));
Thread t2 = new Thread(new IncrementRunnable(longholder));
t1.start();
t2.start();
}
}
UPD: adding another example which is closer to the code I am working on. I would like to remove map entries when no one else is using the object. Please note that reading and writing of the long value happens only inside of remapping function of ConcurrentHashMap.compute:
public class ObjectProvider {
private final ConcurrentMap<Long, CountingObject> map = new ConcurrentHashMap<>();
public CountingObject takeObjectForId(Long id) {
return map.compute(id, (k, v) -> {
CountingObject returnLock;
returnLock = v == null ? new CountingObject() : v;
returnLock.incrementUsages();
return returnLock;
});
}
public void releaseObjectForId(Long id, CountingObject o) {
map.compute(id, (k, v) -> o.decrementUsages() == 0 ? null : o);
}
}
class CountingObject {
private int usages;
public void incrementUsages() {
--usages;
}
public int decrementUsages() {
return --usages;
}
}
UPD2: I admit that I failed to provide the simplest code examples previously, posting a real code now:
public class LockerUtility<T> {
private final ConcurrentMap<T, CountingLock> locks = new ConcurrentHashMap<>();
public void executeLocked(T entityId, Runnable synchronizedCode) {
CountingLock lock = synchronizedTakeEntityLock(entityId);
try {
lock.lock();
try {
synchronizedCode.run();
} finally {
lock.unlock();
}
} finally {
synchronizedReturnEntityLock(entityId, lock);
}
}
private CountingLock synchronizedTakeEntityLock(T id) {
return locks.compute(id, (k, l) -> {
CountingLock returnLock;
returnLock = l == null ? new CountingLock() : l;
returnLock.takeForUsage();
return returnLock;
});
}
private void synchronizedReturnEntityLock(T lockId, CountingLock lock) {
locks.compute(lockId, (i, v) -> lock.returnBack() == 0 ? null : lock);
}
private static class CountingLock extends ReentrantLock {
private volatile long usages = 0;
public void takeForUsage() {
usages++;
}
public long returnBack() {
return --usages;
}
}
}
No, this approach will not work, not even with volatile. You would have to use AtomicLong, LongAdder, or the like, to make this properly thread-safe. ConcurrentHashMap doesn't even work with segmented locks these days.
Also, your test does not prove anything. Concurrency issues by definition don't happen every time. Not even every millionth time.
You must use a proper concurrent Long accumulator like AtomicLong or LongAdder.
Do not get fooled by the line in the documentation of compute:
The entire method invocation is performed atomically
This does work for side-effects, like you have in that value++; it only works for the internal data of ConcurrentHashMap.
The first thing that you miss is that locking in CHM, the implementation has changed a lot (as the other answer has noted). But even if it did not, your understanding of the:
I know that when you explicitly synchronize on a lock, visibility is guaranteed
is flawed. JLS says that this is guaranteed when both the reader and the writer use the same lock; which in your case obviously does not happen; as such no guarantees are in place. In general happens-before guarantees (that you would require here) only work for pairs, for both reader and writer.
I'm trying to count for each minute the records with the same type as in the parameter in a List, in a given time range. Using the following Method:
public Map<String, Object> getCountPerMinuteForType(final String type,
final long startTimestamp,
final long endTimestamp) {
final Map<String, Object> countsPerMinForType = new HashMap<>();
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
int counter = 0;
List<Data> dataList = storage.retrieveData();
for(Data data: dataList){
if (data.getType().equals(type) &&
data.getUnixTimestamp() >= startTimestamp &&
data.getUnixTimestamp() <= endTimestamp){
counter++;
}
}
countsPerMinForType.put(type, counter);
}, 0, 1, TimeUnit.MINUTES);
return countsPerMinForType;
}
The problem is, this method returns an empty Map.
When I print the contents of the Map inside the Executors, I can see that it has data.
It happens because an another thread is performing put operation in the Map. The main thread starts execution of the thread and then returns back to the place where it was called. To solve this issue, you may need to create a listener interface which gets called whenever the second thread performs the task.
Here, below is the code sample which you can use and modify according to your needs.
class Test implements Listener {
private Listener listener;
public Test() {
listener = this; //Set this class as your listener
}
//Make your function return nothing
public void getCountPerMinuteForType(final String type, final long startTimestamp,
final long endTimestamp) {
final Map<String, Object> countsPerMinForType = new HashMap<>();
ScheduledExecutorService service =
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
int counter = 0;
List<Data> dataList = storage.retrieveData();
for (Data data : dataList) {
if (data.getType().equals(type) &&
data.getUnixTimestamp() >= startTimestamp &&
data.getUnixTimestamp() <= endTimestamp) {
counter++;
}
}
listener.onNewData(type, counter);
countsPerMinForType.put(type, counter);
}, 0, 1, TimeUnit.MINUTES);
//return countsPerMinForType;
//If service is terminated call the listener and perform your operation there
if (service.isTerminated()) {
listener.dataFilled(countsPerMinForType);
}
}
#Override
public void onNewData(String str, Object obj) {
//Perform your task here
}
#Override
public void dataFilled(Map<String, Object> data) {
//Perform your task here
}
}
interface Listener {
void dataFilled(Map<String, Object> data);
void onNewData(Map<String, Object> data);
}
The issue you have is that you're expecting the thread you're spinning off has completed the work and the results populated in the countsPerMinForType are returned. This is not what is happening...
What is happening is:
you call the method from the main/current thread of execution
the Map is created
a new thread is spun off to do some work
almost immediately, the method returns and the map is still empty.
...
after the method has completed, the work being performed by the spun off thread is then carried out... and subsequently the calling method never sees the result.
You can confirm this is the case with a test that returns a timestamp for when the getCountPerMinuteForType starts and ends, and another timestamp for when the Thread starts and ends. The start times will be in order, the end times will not be in order.
Also, you may want to consider using a ConcurrentHashMap for a multi-threaded application.
I have a bunch of objects representing some data. These objects can be written to their corresponding files. User may request some changes to be made quicker than previous changes written to the file.
Say, I make changes to File A, File B and File C and submit them for execution. Then, while they are being written, I make changes to File A and post it. For instance, there are 3 threads operating. Once first changes to A, B and C executed (written to files), 1st and 2nd changes to A will be executed almost simultaneously. However, I want the 2nd change to be applied after the 1st one is done.
How can I do that in rxJava?
Another point. In a different place I want to run action with the latest changes. One option is to wait until all tasks finished.
Is there appropriate RxJava primitive/approach that would hopefully cover these 2 use cases?
I am new to RxJava, but I hope this makes sense. Subjects come to my mind as relevant, but there gonna be hundreds of files.
I already have the implementation using custom Executor.
public class OrderingExecutor
implements Executor
{
#Delegate
private final Executor delegate;
private final Map<Object, Queue<Runnable>> keyedTasks = new HashMap<>();
public OrderingExecutor(
Executor delegate)
{
this.delegate = delegate;
}
public void execute(
Runnable task,
Object key)
{
Objects.requireNonNull(key);
boolean first;
Runnable wrappedTask;
synchronized (keyedTasks)
{
Queue<Runnable> dependencyQueue = keyedTasks.get(key);
first = (dependencyQueue == null);
if (dependencyQueue == null)
{
dependencyQueue = new LinkedList<>();
keyedTasks.put(key, dependencyQueue);
}
wrappedTask = wrap(task, dependencyQueue, key);
if (!first)
{
dependencyQueue.add(wrappedTask);
}
}
// execute method can block, call it outside synchronize block
if (first)
{
delegate.execute(wrappedTask);
}
}
private Runnable wrap(
Runnable task,
Queue<Runnable> dependencyQueue,
Object key)
{
return new OrderedTask(task, dependencyQueue, key);
}
class OrderedTask
implements Runnable
{
private final Queue<Runnable> dependencyQueue;
private final Runnable task;
private final Object key;
public OrderedTask(
Runnable task,
Queue<Runnable> dependencyQueue,
Object key)
{
this.task = task;
this.dependencyQueue = dependencyQueue;
this.key = key;
}
#Override
public void run()
{
try
{
task.run();
}
finally
{
Runnable nextTask = null;
synchronized (keyedTasks)
{
if (dependencyQueue.isEmpty())
{
keyedTasks.remove(key);
}
else
{
nextTask = dependencyQueue.poll();
}
}
if (nextTask != null)
{
delegate.execute(nextTask);
}
}
}
}
}
Maybe some sensible way to plug it into rxJava?
It's not fully clear what you try to achieve here, but you can layer a priority queue on
top of RxJava.
class OrderedTask implements Comparable<OrderedTask> { ... }
PriorityBlockingQueue<OrderedTask> queue = new PriorityBlockingQueue<>();
PublishSubject<Integer> trigger = PublishSubject.create();
trigger.flatMap(v -> {
OrderedTask t = queue.poll();
return someAPI.workWith(t);
}, 1)
.subscribe(result -> { }, error -> { });
queue.offer(new SomeOrderedTask(1));
trigger.onNext(1);
queue.offer(new SomeOrderedTask(2));
trigger.onNext(2);
I need a way to allow only one thread to modify data related to a service ticket. More than one thread may be attempting to modify the ticket data at the same time.
Below is a simplified version of my approach. Is there a better way to do this? Maybe with java.util.concurrent packages?
public class SomeClass1
{
static final HashMap<Integer, Object> ticketLockMap = new HashMap<Integer, Object>();
public void process(int ticketNumber)
{
synchronized (getTicketLock(ticketNumber))
{
// only one thread may modify ticket data here
// ... ticket modifications here...
}
}
protected static Object getTicketLock(int ticketNumber)
{
Object ticketLock;
// allow only one thread to use map
synchronized (ticketLockMap)
{
ticketLock = ticketLockMap.get(ticketNumber);
if (ticketLock == null)
{
// first time ticket is locked
ticketLock = new Object();
ticketLockMap.put(ticketNumber, ticketLock);
}
}
return ticketLock;
}
}
Additionally, if I don't want the HashMap filling up with unused locks, I would need a more complex approach like the following:
public class SomeClass2
{
static final HashMap<Integer, Lock> ticketLockMap = new HashMap<Integer, Lock>();
public void process(int ticketNumber)
{
synchronized (getTicketLock(ticketNumber))
{
// only one thread may modify ticket data here
// ... ticket modifications here...
// after all modifications, release lock
releaseTicketLock(ticketNumber);
}
}
protected static Lock getTicketLock(int ticketNumber)
{
Lock ticketLock;
// allow only one thread to use map
synchronized (ticketLockMap)
{
ticketLock = ticketLockMap.get(ticketNumber);
if (ticketLock == null)
{
// first time ticket is locked
ticketLock = new Lock();
ticketLockMap.put(ticketNumber, ticketLock);
}
}
return ticketLock;
}
protected static void releaseTicketLock(int ticketNumber)
{
// allow only one thread to use map
synchronized (ticketLockMap)
{
Lock ticketLock = ticketLockMap.get(ticketNumber);
if (ticketLock != null && --ticketLock.inUseCount == 0)
{
// lock no longer in use
ticketLockMap.remove(ticketLock);
}
}
}
}
class Lock
{
// constructor/getters/setters omitted for brevity
int inUseCount = 1;
}
You might be looking for the Lock interface. The second case could be solved by a ReentrantLock, which counts the number of times it has been locked.
Locks have a .lock() method which waits for the lock to acquire and an .unlock method which should be called like
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
This could then be combined with a HashMap<Integer, Lock>. You could omit the synchronized calls and cut down on lines of code.
I had posted somewhat similar question before also. I got clarification for my doubts as well. But still I need something more. The Hashmap will be initialized with the enum object as the key and a threadpool instance as the value. I am confused as of how to initialize the HashMap for every object been called by some other process ..To make clear :
My program, MyThreadpoolExcecutorPgm.java initializes a HashMap
My Progran AdditionHandler.java requests a thread from the HashMap by passing ThreadpoolName (enum). I am getting "No thread available from HashMap" message. Please do help me.
Below given is my code:
public class MyThreadpoolExcecutorPgm {
enum ThreadpoolName {
DR, BR, SV, MISCELLENEOUS;
}
private static String threadName;
private static HashMap<ThreadpoolName, ThreadPoolExecutor>
threadpoolExecutorHash;
public MyThreadpoolExcecutorPgm(String p_threadName) {
threadName = p_threadName;
}
public static void fillthreadpoolExecutorHash() {
int poolsize = 3;
int maxpoolsize = 3;
long keepAliveTime = 10;
ThreadPoolExecutor tp = null;
threadpoolExecutorHash = new HashMap<ThreadpoolName, ThreadPoolExecutor>();
for (ThreadpoolName poolName : ThreadpoolName.) // failing to implement
{
tp = new ThreadPoolExecutor(poolsize, maxpoolsize, keepAliveTime,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5));
threadpoolExecutorHash.put(poolName, tp);
}
}
public static ThreadPoolExecutor getThreadpoolExcecutor(
ThreadpoolName poolName) {
ThreadPoolExecutor thread = null;
if (threadpoolExecutorHash != null && poolName != null) {
thread = threadpoolExecutorHash.get(poolName);
} else {
System.out.println("No thread available from HashMap");
}
return thread;
}
}
AdditionHandler.java
public class AdditionHandler{
public void handle() {
AddProcess setObj = new AddProcess(5, 20);
ThreadPoolExecutor tpe = null;
ThreadpoolName poolName =ThreadpoolName.DR; //i am using my enum
tpe = MyThreadpoolExcecutorPgm.getThreadpoolExcecutor(poolName);
tpe.execute(setObj);
}
public static void main(String[] args) {
AdditionHandler obj = new AdditionHandler();
obj.handle();
}
}
I suspect you're just looking for the static values() method which is added to every enum:
for (ThreadpoolName poolName : ThreadpoolName.getValues())
Alternatively, you can use EnumSet.allOf():
for (ThreadpoolName poolName : EnumSet.allOf(ThreadpoolName.class))
(As Bozho says, EnumMap is a good alternative here. You still need to loop through the enum values.)
First, you'd better use EnumMap. Then make sure you have filled the map before you invoked the method.
You can iterate through enum values by one of (in descending order of preference)
for(Enum value : Enum.values())
for(Enum value : EnumSet.allOf(Enum.class))
for(Enum value : Enum.class.getEnumConstants())
But you should also be using an EnumMap.