Top Description Inners Methods
com.google.inject.internal

pack-priv Interface CycleDetectingLock<ID>

Known Direct Implementers
com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock
Type Parameters
<ID>
Lock identification provided by the client, is returned unmodified to the client when lock cycle is detected to identify it. Only toString() needs to be implemented. Lock references this object internally, for the purposes of Garbage Collection you should not use heavy IDs. Lock is referenced by a lock factory as long as it's owned by a thread.
Imports
com.google.common.base.Preconditions, com.google.common.collect.ImmutableListMultimap, .LinkedHashMultimap, .ListMultimap, .Maps, .Multimap, .MultimapBuilder, java.util.Collection, .Map, java.util.concurrent.locks.Lock, .ReentrantLock

Simplified version of Lock that is special due to how it handles deadlocks detection.

Is an inherent part of SingletonScope, moved into a upper level class due to its size and complexity.

Author
timofeyb (Timothy Basanov)
See Also
SingletonScope, com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory

Nested and Inner Type Summary

Modifier and TypeClass and Description
public static class
CycleDetectingLock.CycleDetectingLockFactory<ID>

Wraps locks so they would never cause a deadlock.

Method Summary

Modifier and TypeMethod and Description
public ListMultimap<Thread, ID>
lockOrDetectPotentialLocksCycle()

Takes a lock in a blocking fashion in case no potential deadlocks are detected.

public void
unlock()

Unlocks previously locked lock.

Method Detail

lockOrDetectPotentialLocksCycleback to summary
public ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle()

Takes a lock in a blocking fashion in case no potential deadlocks are detected. If the lock was successfully owned, returns an empty map indicating no detected potential deadlocks.

Otherwise, a map indicating threads involved in a potential deadlock are returned. Map is ordered by dependency cycle and lists locks for each thread that are part of the loop in order, the last lock in the list is the one that the thread is currently waiting for. Returned map is created atomically.

In case no cycle is detected performance is O(threads creating singletons), in case cycle is detected performance is O(singleton locks).

unlockback to summary
public void unlock()

Unlocks previously locked lock.

com.google.inject.internal back to summary

public Class CycleDetectingLock.CycleDetectingLockFactory<ID>

extends Object
Class Inheritance
  • java.lang.Object
  • com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory

Wraps locks so they would never cause a deadlock. On each CycleDetectingLock#lockOrDetectPotentialLocksCycle we check for dependency cycles within locks created by the same factory. Either we detect a cycle and return it or take it atomically.

Important to note that we do not prevent deadlocks in the client code. As an example: Thread A takes lock L and creates singleton class CA depending on the singleton class CB. Meanwhile thread B is creating class CB and is waiting on the lock L. Issue happens due to client code creating interdependent classes and using locks, where no guarantees on the creation order from Guice are provided.

Instances of these locks are not intended to be exposed outside of SingletonScope.

Nested and Inner Type Summary

Modifier and TypeClass and Description
pack-priv static class

Field Summary

Modifier and TypeField and Description
private static final Multimap<Thread, CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?>>
locksOwnedByThread

Lists locks that thread owns.

private static Map<Thread, CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?>>
lockThreadIsWaitingOn

Specifies lock that thread is currently waiting on to own it.

Constructor Summary

AccessConstructor and Description
public

Method Summary

Modifier and TypeMethod and Description
pack-priv CycleDetectingLock<ID>
create(ID
lock id that would be used to report lock cycles if detected
userLockId
)

Creates new lock within this factory context.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

locksOwnedByThreadback to summary
private static final Multimap<Thread, CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?>> locksOwnedByThread

Lists locks that thread owns. Used only to populate locks in a potential cycle when it is detected.

  • Key: thread
  • Value: stack of locks that were owned.

Element is added inside lockOrDetectPotentialLocksCycle() after Lock#lock is called. Element is removed inside unlock() synchronously with Lock#unlock() call.

Same lock can only be present several times for the same thread as locks are reentrant. Lock can not be owned by several different threads as the same time.

Guarded by CycleDetectingLockFactory.class.

lockThreadIsWaitingOnback to summary
private static Map<Thread, CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?>> lockThreadIsWaitingOn

Specifies lock that thread is currently waiting on to own it. Used only for purposes of locks cycle detection.

  • Key: thread
  • Value: lock that is being waited on

Element is added inside lockOrDetectPotentialLocksCycle() before Lock#lock is called. Element is removed inside lockOrDetectPotentialLocksCycle() after Lock#lock and synchronously with adding it to locksOwnedByThread.

Same lock can be added for several threads in case all of them are trying to take it.

Guarded by CycleDetectingLockFactory.class.

Constructor Detail

CycleDetectingLockFactoryback to summary
public CycleDetectingLockFactory()

Method Detail

createback to summary
pack-priv CycleDetectingLock<ID> create(ID userLockId)

Creates new lock within this factory context. We can guarantee that locks created by the same factory would not deadlock.

Parameters
userLockId:ID

lock id that would be used to report lock cycles if detected

com.google.inject.internal back to summary

pack-priv Class CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<ID>

extends Object
implements CycleDetectingLock<ID>
Class Inheritance
  • java.lang.Object
  • com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock
All Implemented Interfaces
com.google.inject.internal.CycleDetectingLock

The implementation for CycleDetectingLock.

Field Summary

Modifier and TypeField and Description
private final CycleDetectingLock.CycleDetectingLockFactory<ID>
lockFactory

Factory that was used to create this lock.

private final Lock
lockImplementation

Underlying lock used for actual waiting when no potential deadlocks are detected.

private Thread
lockOwnerThread

Thread that owns this lock.

private int
lockReentranceCount

Number of times that thread owned this lock.

private final ID
userLockId

User id for this lock.

Constructor Summary

AccessConstructor and Description
pack-priv
ReentrantCycleDetectingLock(CycleDetectingLock.CycleDetectingLockFactory<ID> lockFactory, ID userLockId, Lock lockImplementation)

Method Summary

Modifier and TypeMethod and Description
private CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?>
addAllLockIdsAfter(Thread thread, CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?> lock, ListMultimap<Thread, ID> potentialLocksCycle)

Adds all locks held by the given thread that are after the given lock and then returns the lock the thread is currently waiting on, if any

pack-priv void
checkState()

Check consistency of an internal state.

private ListMultimap<Thread, ID>
detectPotentialLocksCycle()

Algorithm to detect a potential lock cycle.

public ListMultimap<Thread, ID>
lockOrDetectPotentialLocksCycle()

Implements com.google.inject.internal.CycleDetectingLock.lockOrDetectPotentialLocksCycle.

Takes a lock in a blocking fashion in case no potential deadlocks are detected.
public String
toString()

Overrides java.lang.Object.toString.

Returns a string representation of the object.
public void
unlock()

Implements com.google.inject.internal.CycleDetectingLock.unlock.

Unlocks previously locked lock.
Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAllwaitwaitwait

Field Detail

lockFactoryback to summary
private final CycleDetectingLock.CycleDetectingLockFactory<ID> lockFactory

Factory that was used to create this lock.

lockImplementationback to summary
private final Lock lockImplementation

Underlying lock used for actual waiting when no potential deadlocks are detected.

lockOwnerThreadback to summary
private Thread lockOwnerThread

Thread that owns this lock. Nullable. Guarded by CycleDetectingLockFactory.this.

lockReentranceCountback to summary
private int lockReentranceCount

Number of times that thread owned this lock. Guarded by CycleDetectingLockFactory.this.

userLockIdback to summary
private final ID userLockId

User id for this lock.

Constructor Detail

ReentrantCycleDetectingLockback to summary
pack-priv ReentrantCycleDetectingLock(CycleDetectingLock.CycleDetectingLockFactory<ID> lockFactory, ID userLockId, Lock lockImplementation)

Method Detail

addAllLockIdsAfterback to summary
private CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?> addAllLockIdsAfter(Thread thread, CycleDetectingLock.CycleDetectingLockFactory.ReentrantCycleDetectingLock<?> lock, ListMultimap<Thread, ID> potentialLocksCycle)

Adds all locks held by the given thread that are after the given lock and then returns the lock the thread is currently waiting on, if any

checkStateback to summary
pack-priv void checkState() throws IllegalStateException

Check consistency of an internal state.

detectPotentialLocksCycleback to summary
private ListMultimap<Thread, ID> detectPotentialLocksCycle()

Algorithm to detect a potential lock cycle.

For lock's thread owner check which lock is it trying to take. Repeat recursively. When current thread is found a potential cycle is detected.

See Also
CycleDetectingLock#lockOrDetectPotentialLocksCycle()
lockOrDetectPotentialLocksCycleback to summary
public ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle()

Implements com.google.inject.internal.CycleDetectingLock.lockOrDetectPotentialLocksCycle.

Doc from com.google.inject.internal.CycleDetectingLock.lockOrDetectPotentialLocksCycle.

Takes a lock in a blocking fashion in case no potential deadlocks are detected. If the lock was successfully owned, returns an empty map indicating no detected potential deadlocks.

Otherwise, a map indicating threads involved in a potential deadlock are returned. Map is ordered by dependency cycle and lists locks for each thread that are part of the loop in order, the last lock in the list is the one that the thread is currently waiting for. Returned map is created atomically.

In case no cycle is detected performance is O(threads creating singletons), in case cycle is detected performance is O(singleton locks).

Annotations
@Override
toStringback to summary
public String toString()

Overrides java.lang.Object.toString.

Doc from java.lang.Object.toString.

Returns a string representation of the object.

Returns:String

a string representation of the object

Annotations
@Override
unlockback to summary
public void unlock()

Implements com.google.inject.internal.CycleDetectingLock.unlock.

Doc from com.google.inject.internal.CycleDetectingLock.unlock.

Unlocks previously locked lock.

Annotations
@Override