Skip to content
This repository was archived by the owner on Feb 25, 2024. It is now read-only.

Commit 97d9cf1

Browse files
committed
update SubmissionPublisher to CVS rev. 1.83
1 parent 2017c22 commit 97d9cf1

File tree

1 file changed

+67
-20
lines changed

1 file changed

+67
-20
lines changed

src/main/java/java9/util/concurrent/SubmissionPublisher.java

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import java.util.concurrent.RejectedExecutionException;
1515
import java.util.concurrent.TimeUnit;
1616
import java.util.concurrent.locks.LockSupport;
17+
import java.util.concurrent.locks.ReentrantLock;
1718

1819
import java9.util.Objects;
1920
import java9.util.function.BiConsumer;
@@ -146,15 +147,15 @@
146147
* @since 9
147148
*/
148149
public class SubmissionPublisher<T> implements Publisher<T> {
149-
// CVS rev. 1.81
150+
// CVS rev. 1.83
150151
/*
151152
* Most mechanics are handled by BufferedSubscription. This class
152153
* mainly tracks subscribers and ensures sequentiality, by using
153-
* built-in synchronization locks across public methods. Using
154-
* built-in locks works well in the most typical case in which
155-
* only one thread submits items. We extend this idea in
156-
* submission methods by detecting single-ownership to reduce
157-
* producer-consumer synchronization strength.
154+
* locks across public methods, to ensure thread-safety in the
155+
* presence of multiple sources and maintain acquire-release
156+
* ordering around user operations. However, we also track whether
157+
* there is only a single source, and if so streamline some buffer
158+
* operations by avoiding some atomics.
158159
*/
159160

160161
/** The largest possible power of two array size. */
@@ -209,6 +210,8 @@ private static final class ThreadPerTaskExecutor implements Executor {
209210
*/
210211
BufferedSubscription<T> clients;
211212

213+
/** Lock for exclusion across multiple sources */
214+
final ReentrantLock lock;
212215
/** Run status, updated only within locks */
213216
volatile boolean closed;
214217
/** Set true on first call to subscribe, to initialize possible owner */
@@ -248,6 +251,7 @@ public SubmissionPublisher(Executor executor, int maxBufferCapacity,
248251
Objects.requireNonNull(executor);
249252
if (maxBufferCapacity <= 0)
250253
throw new IllegalArgumentException("capacity must be positive");
254+
this.lock = new ReentrantLock();
251255
this.executor = executor;
252256
this.onNextHandler = handler;
253257
this.maxBufferCapacity = roundCapacity(maxBufferCapacity);
@@ -311,13 +315,15 @@ public SubmissionPublisher() {
311315
*/
312316
public void subscribe(Subscriber<? super T> subscriber) {
313317
Objects.requireNonNull(subscriber);
318+
ReentrantLock lock = this.lock;
314319
int max = maxBufferCapacity; // allocate initial array
315320
Object[] array = new Object[max < INITIAL_CAPACITY ?
316321
max : INITIAL_CAPACITY];
317322
BufferedSubscription<T> subscription =
318323
new BufferedSubscription<T>(subscriber, executor, onNextHandler,
319324
array, max);
320-
synchronized (this) {
325+
lock.lock();
326+
try {
321327
if (!subscribed) {
322328
subscribed = true;
323329
owner = Thread.currentThread();
@@ -352,6 +358,8 @@ else if (subscriber.equals(b.subscriber)) {
352358
pred = b;
353359
b = next;
354360
}
361+
} finally {
362+
lock.unlock();
355363
}
356364
}
357365

@@ -364,7 +372,9 @@ private int doOffer(T item, long nanos,
364372
Objects.requireNonNull(item);
365373
int lag = 0;
366374
boolean complete, unowned;
367-
synchronized (this) {
375+
ReentrantLock lock = this.lock;
376+
lock.lock();
377+
try {
368378
Thread t = Thread.currentThread(), o;
369379
BufferedSubscription<T> b = clients;
370380
if ((unowned = ((o = owner) != t)) && o != null)
@@ -395,6 +405,8 @@ else if (stat > lag)
395405
if (retries != null || cleanMe)
396406
lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
397407
}
408+
} finally {
409+
lock.unlock();
398410
}
399411
if (complete)
400412
throw new IllegalStateException("Closed");
@@ -583,14 +595,18 @@ public int offer(T item, long timeout, TimeUnit unit,
583595
* subscribers have yet completed.
584596
*/
585597
public void close() {
598+
ReentrantLock lock = this.lock;
586599
if (!closed) {
587600
BufferedSubscription<T> b;
588-
synchronized (this) {
601+
lock.lock();
602+
try {
589603
// no need to re-check closed here
590604
b = clients;
591605
clients = null;
592606
owner = null;
593607
closed = true;
608+
} finally {
609+
lock.unlock();
594610
}
595611
while (b != null) {
596612
BufferedSubscription<T> next = b.next;
@@ -614,16 +630,20 @@ public void close() {
614630
*/
615631
public void closeExceptionally(Throwable error) {
616632
Objects.requireNonNull(error);
633+
ReentrantLock lock = this.lock;
617634
if (!closed) {
618635
BufferedSubscription<T> b;
619-
synchronized (this) {
636+
lock.lock();
637+
try {
620638
b = clients;
621639
if (!closed) { // don't clobber racing close
622640
closedException = error;
623641
clients = null;
624642
owner = null;
625643
closed = true;
626644
}
645+
} finally {
646+
lock.unlock();
627647
}
628648
while (b != null) {
629649
BufferedSubscription<T> next = b.next;
@@ -661,7 +681,9 @@ public Throwable getClosedException() {
661681
*/
662682
public boolean hasSubscribers() {
663683
boolean nonEmpty = false;
664-
synchronized (this) {
684+
ReentrantLock lock = this.lock;
685+
lock.lock();
686+
try {
665687
for (BufferedSubscription<T> b = clients; b != null;) {
666688
BufferedSubscription<T> next = b.next;
667689
if (b.isClosed()) {
@@ -673,6 +695,8 @@ public boolean hasSubscribers() {
673695
break;
674696
}
675697
}
698+
} finally {
699+
lock.unlock();
676700
}
677701
return nonEmpty;
678702
}
@@ -683,9 +707,15 @@ public boolean hasSubscribers() {
683707
* @return the number of current subscribers
684708
*/
685709
public int getNumberOfSubscribers() {
686-
synchronized (this) {
687-
return cleanAndCount();
710+
int n;
711+
ReentrantLock lock = this.lock;
712+
lock.lock();
713+
try {
714+
n = cleanAndCount();
715+
} finally {
716+
lock.unlock();
688717
}
718+
return n;
689719
}
690720

691721
/**
@@ -715,7 +745,9 @@ public int getMaxBufferCapacity() {
715745
*/
716746
public List<Subscriber<? super T>> getSubscribers() {
717747
ArrayList<Subscriber<? super T>> subs = new ArrayList<Subscriber<? super T>>();
718-
synchronized (this) {
748+
ReentrantLock lock = this.lock;
749+
lock.lock();
750+
try {
719751
BufferedSubscription<T> pred = null, next;
720752
for (BufferedSubscription<T> b = clients; b != null; b = next) {
721753
next = b.next;
@@ -731,6 +763,8 @@ public List<Subscriber<? super T>> getSubscribers() {
731763
pred = b;
732764
}
733765
}
766+
} finally {
767+
lock.unlock();
734768
}
735769
return subs;
736770
}
@@ -744,8 +778,11 @@ public List<Subscriber<? super T>> getSubscribers() {
744778
*/
745779
public boolean isSubscribed(Subscriber<? super T> subscriber) {
746780
Objects.requireNonNull(subscriber);
781+
boolean subscribed = false;
782+
ReentrantLock lock = this.lock;
747783
if (!closed) {
748-
synchronized (this) {
784+
lock.lock();
785+
try {
749786
BufferedSubscription<T> pred = null, next;
750787
for (BufferedSubscription<T> b = clients; b != null; b = next) {
751788
next = b.next;
@@ -756,14 +793,16 @@ public boolean isSubscribed(Subscriber<? super T> subscriber) {
756793
else
757794
pred.next = next;
758795
}
759-
else if (subscriber.equals(b.subscriber))
760-
return true;
796+
else if (subscribed = subscriber.equals(b.subscriber))
797+
break;
761798
else
762799
pred = b;
763800
}
801+
} finally {
802+
lock.unlock();
764803
}
765804
}
766-
return false;
805+
return subscribed;
767806
}
768807

769808
/**
@@ -776,7 +815,9 @@ else if (subscriber.equals(b.subscriber))
776815
public long estimateMinimumDemand() {
777816
long min = Long.MAX_VALUE;
778817
boolean nonEmpty = false;
779-
synchronized (this) {
818+
ReentrantLock lock = this.lock;
819+
lock.lock();
820+
try {
780821
BufferedSubscription<T> pred = null, next;
781822
for (BufferedSubscription<T> b = clients; b != null; b = next) {
782823
int n; long d;
@@ -795,6 +836,8 @@ public long estimateMinimumDemand() {
795836
pred = b;
796837
}
797838
}
839+
} finally {
840+
lock.unlock();
798841
}
799842
return nonEmpty ? min : 0;
800843
}
@@ -807,7 +850,9 @@ public long estimateMinimumDemand() {
807850
*/
808851
public int estimateMaximumLag() {
809852
int max = 0;
810-
synchronized (this) {
853+
ReentrantLock lock = this.lock;
854+
lock.lock();
855+
try {
811856
BufferedSubscription<T> pred = null, next;
812857
for (BufferedSubscription<T> b = clients; b != null; b = next) {
813858
int n;
@@ -825,6 +870,8 @@ public int estimateMaximumLag() {
825870
pred = b;
826871
}
827872
}
873+
} finally {
874+
lock.unlock();
828875
}
829876
return max;
830877
}

0 commit comments

Comments
 (0)