2

I have a ReentrantLock in my code and want to use it to clear an array once per second; I dont want other threads to change the array while it is being cleared, but if I am not currently clearing the array other threads shall not have to wait, like this:

public void addToArray(Object a) {
    lock.waitforunlock(); //not a real method just to clarify my intentions
    array.add(a);
}

To better clarify my intentions I will explain the process: the netty eventloop will call my network handler, that network handler will then call the addToArray method from before, once per second my main thread that will never be a Netty thread will clear the array, in this time every netty thread shall have to wait until this is finished! Note: the addToArray method is threadproof and I dont want to sync it because then the hole point of a event loop is useless.

Warren Dew
  • 8,790
  • 3
  • 30
  • 44
Lost2
  • 138
  • 1
  • 13
  • Have you considered using a [ReentrantReadWriteLock](https://stackoverflow.com/a/18354623/823393)? – OldCurmudgeon Apr 06 '18 at 15:21
  • Yes, but that also dosent have my desired function – Lost2 Apr 06 '18 at 15:29
  • 1
    If you just wait until it is unlocked it may become locked while you are working on it. It would be safer to take a write lock before clearing or adding and a read lock on access. There is very little cost to taking an uncontested lock. – OldCurmudgeon Apr 06 '18 at 15:40
  • how about calling [`lock.tryLock()`](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html#tryLock())? – Solomon Slow Apr 06 '18 at 16:38
  • Would the same thread be trying to clear the array, or would that be a different thread? If the same thread, would the clear array code be calling this method? Would the array.add() method call the array clearing method? If none of those are true, then you can just lock the lock; the fact that it's reentrant won't make a difference. – Warren Dew Apr 06 '18 at 17:36
  • @jameslarge the lock.trylock() will only lock if the lock is unlocked i want the addtoArrayMethod only to be locked wenn the lock is locked by the clearing method – Lost2 Apr 06 '18 at 18:30
  • I don't understand. How many threads are there? Which thread has locked the lock? Which thread is clearing the array? Which thread is calling `addToArray(a)`? I think you will need to show a more complete example if you want to get a meaningful answer. – Solomon Slow Apr 06 '18 at 18:53
  • 1
    @jameslarge i added sum more detailed explantion, mabe now you will understand my problem – Lost2 Apr 07 '18 at 00:05

2 Answers2

3

There is no API method that does exactly what you are asking.

The most efficient way to do it is like this:

try {
    lock.lock();
} finally {
    lock.unlock();
}

In other words, grab the lock momentarily then release it.

But here's the problem.

  1. In general, the instant you release the lock, some other thread might immediately grab it. So your array.add() call may happen simultaneously with some other thread doing things to array. Even if your use-case means that another thread grabbing the lock is highly unlikely, it can still happen; e.g. if your server is under severe load and the current thread gets preempted immediately after releasing the lock.

  2. Presumably you are performing memory writes in array.add(). Unless they are performed with appropriate synchronization, those updates may not be visible to other threads. (You say "addToArray method is threadproof", but without a clear, detailed explanation of what you mean by that, I would be uncomfortable with saying this code is thread safe.)

  3. If what you are trying to do here is to array.add() after something else has happened, then testing the lock / waiting for it to be released doesn't tell you if the event actually happened. All it tells you is that it wasn't happening at the instant that the test succeeded.

In short, I doubt that waiting for a lock to be released before doing an update is actually a correct solution ... no matter how you implement the waiting.


Another way to look at this.

  • If array.add() is completely threadsafe, and will work correctly irrespective of some other thread holding the lock, why do you need to test the lock? Just call the method.

  • If you are actually trying to have the array.add() call happen after some event that coincides with the lock being released, use a cyclic barrier or similar.


Note: I read and tried to understand your explanation, but I got lost with what you are saying. Due to "language issues" I think.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

As I understand it, you have two or more separate threads mutating a list: the main thread occasionally clearing the list, and the netty thread adding to the list. You want to make sure they don't both attempt to modify the list at the same time.

The simplest solution to this is to use a thread safe list, and make sure the main thread uses the List.clear() method to clear the list. That way, the clear() call will be atomic - once started it will finish before any other accesses to the list - so you won't have to worry about adding to the list "in the middle of" the clear() call.

In a comment to another answer, you mention that you are using a CopyOnWriteArrayList, which is thread safe. Thus, you can just call add() the code that adds to the list without worrying about synchronization; the add() call will automatically wait if the list is being cleared, and proceed otherwise. You can also remove the use of the ReentrantLock from your main thread unless there are other reasons, besides protecting this list, to use the lock.

Warren Dew
  • 8,790
  • 3
  • 30
  • 44