1+ package com .antkorwin .xsync ;
2+
3+ import java .util .Objects ;
4+ import java .util .concurrent .ConcurrentMap ;
5+ import java .util .concurrent .locks .ReadWriteLock ;
6+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
7+ import java .util .concurrent .locks .StampedLock ;
8+ import java .util .function .Supplier ;
9+
10+ import org .hibernate .validator .internal .util .ConcurrentReferenceHashMap ;
11+
12+ /**
13+ * Created on 22.06.2020.
14+ * <p>
15+ * The factory of {@link ReadWriteLock ReadWriteLocks}, based on
16+ * {@link ConcurrentReferenceHashMap}. Use this if you need to allow
17+ * multiple concurrent readers but only one writer. You can also control
18+ * whether or not to support reentrancy and whether or not the lock should
19+ * be fair. Depending on your usage patterns, you may opt to back the
20+ * locks with a {@link ReentrantReadWriteLock} (default) or a
21+ * {@link StampedLock}. Note, for a stamped lock, the optimistic locking
22+ * model and lock type modification are not supported.
23+ * </p>
24+ *
25+ * @author Carlos Macasaet
26+ */
27+ public class ReadWriteLockFactory <KeyT > {
28+
29+ private static final int DEFAULT_INITIAL_CAPACITY = 16 ;
30+ private static final float DEFAULT_LOAD_FACTOR = 0.75f ;
31+ private static final int DEFAULT_CONCURRENCY_LEVEL = 16 ;
32+ private static final ConcurrentReferenceHashMap .ReferenceType DEFAULT_REFERENCE_TYPE =
33+ ConcurrentReferenceHashMap .ReferenceType .WEAK ;
34+
35+ private final ConcurrentMap <KeyT , ReadWriteLock > map ;
36+ private final Supplier <? extends ReadWriteLock > lockSupplier ;
37+
38+ /**
39+ * Create a lock factory with default settings
40+ */
41+ public ReadWriteLockFactory () {
42+ this (DEFAULT_CONCURRENCY_LEVEL , DEFAULT_REFERENCE_TYPE );
43+ }
44+
45+ /**
46+ * Create a lock factory with default settings and a custom lock generator.
47+ *
48+ * @param lockSupplier a method for creating new {@link ReadWriteLock} instances.
49+ */
50+ public ReadWriteLockFactory (final Supplier <? extends ReadWriteLock > lockSupplier ) {
51+ this (DEFAULT_CONCURRENCY_LEVEL , DEFAULT_REFERENCE_TYPE , lockSupplier );
52+ }
53+
54+ /**
55+ * Create a lock factory with custom settings
56+ *
57+ * @param concurrencyLevel the expected number of threads
58+ * that will concurrently write to the map
59+ * @param referenceType the reference type used for entries (soft or weak)
60+ */
61+ public ReadWriteLockFactory (int concurrencyLevel , ConcurrentReferenceHashMap .ReferenceType referenceType ) {
62+ this (concurrencyLevel , referenceType , ReentrantReadWriteLock ::new );
63+ }
64+
65+ /**
66+ * Create a lock factory with custom settings
67+ *
68+ * @param concurrencyLevel the expected number of threads
69+ * that will concurrently write to the map
70+ * @param referenceType the reference type used for entries (soft or weak)
71+ * @param lockSupplier a method for creating ReadWriteLock instances
72+ */
73+ public ReadWriteLockFactory (final int concurrencyLevel , final ConcurrentReferenceHashMap .ReferenceType referenceType ,
74+ final Supplier <? extends ReadWriteLock > lockSupplier ) {
75+ this (new ConcurrentReferenceHashMap <>(DEFAULT_INITIAL_CAPACITY ,
76+ DEFAULT_LOAD_FACTOR ,
77+ concurrencyLevel ,
78+ referenceType ,
79+ referenceType ,
80+ null ),
81+ lockSupplier );
82+ }
83+
84+ protected ReadWriteLockFactory (final ConcurrentMap <KeyT , ReadWriteLock > map ,
85+ final Supplier <? extends ReadWriteLock > lockSupplier ) {
86+ Objects .requireNonNull (map , "map must be provided" );
87+ Objects .requireNonNull (lockSupplier , "lockSupplier must be provided" );
88+ this .map = map ;
89+ this .lockSupplier = lockSupplier ;
90+ }
91+
92+ /**
93+ * Creates and returns a lock by the key.
94+ * If the lock for this key already exists in the weak-map,
95+ * then returns the same reference of the lock.
96+ *
97+ * @param key object which used as a key for synchronization
98+ * @return lock instance created for this key
99+ */
100+ public ReadWriteLock getReadWriteLock (KeyT key ) {
101+ return this .map .computeIfAbsent (key , k -> lockSupplier .get ());
102+ }
103+
104+ /**
105+ * @return count of locks in this factory.
106+ */
107+ public long size () {
108+ return this .map .size ();
109+ }
110+
111+ }
0 commit comments