-
Notifications
You must be signed in to change notification settings - Fork 7.6k
1.x: compact MultipleAssignment- and Serial-Subscriptions #4328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/** | ||
* Copyright 2014 Netflix, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package rx.internal.subscriptions; | ||
|
||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
import rx.Subscription; | ||
import rx.subscriptions.Subscriptions; | ||
|
||
/** | ||
* A container of a Subscription that supports operations of SerialSubscription | ||
* and MultipleAssignmentSubscription via methods (update, replace) and extends | ||
* AtomicReference to reduce allocation count (beware the API leak of AtomicReference!). | ||
* @since 1.1.9 | ||
*/ | ||
public final class SequentialSubscription extends AtomicReference<Subscription> implements Subscription { | ||
|
||
/** */ | ||
private static final long serialVersionUID = 995205034283130269L; | ||
|
||
/** | ||
* Create an empty SequentialSubscription. | ||
*/ | ||
public SequentialSubscription() { | ||
|
||
} | ||
|
||
/** | ||
* Create a SequentialSubscription with the given initial Subscription. | ||
* @param initial the initial Subscription, may be null | ||
*/ | ||
public SequentialSubscription(Subscription initial) { | ||
lazySet(initial); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any reason to prefer this over There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The super constructor uses a full barrier volatile write. |
||
} | ||
|
||
/** | ||
* Returns the current contained Subscription (may be null). | ||
* <p>(Remark: named as such because get() is final). | ||
* @return the current contained Subscription (may be null) | ||
*/ | ||
public Subscription current() { | ||
Subscription current = super.get(); | ||
if (current == Unsubscribed.INSTANCE) { | ||
return Subscriptions.unsubscribed(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or you want them to be different objects? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be great if its name somehow show that it's internal only so we could pay more attention to leaking it during code reviews There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The package name and javadoc indicates it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, though they're ~invisible during code review |
||
} | ||
return current; | ||
} | ||
|
||
/** | ||
* Atomically sets the contained Subscription to the provided next value and unsubscribes | ||
* the previous value or unsubscribes the next value if this container is unsubscribed. | ||
* <p>(Remark: named as such because set() is final). | ||
* @param next the next Subscription to contain, may be null | ||
* @return true if the update succeded, false if the container was unsubscribed | ||
*/ | ||
public boolean update(Subscription next) { | ||
for (;;) { | ||
Subscription current = get(); | ||
|
||
if (current == Unsubscribed.INSTANCE) { | ||
if (next != null) { | ||
next.unsubscribe(); | ||
} | ||
return false; | ||
} | ||
|
||
if (compareAndSet(current, next)) { | ||
if (current != null) { | ||
current.unsubscribe(); | ||
} | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Atomically replaces the contained Subscription to the provided next value but | ||
* does not unsubscribe the previous value or unsubscribes the next value if this | ||
* container is unsubscribed. | ||
* @param next the next Subscription to contain, may be null | ||
* @return true if the update succeded, false if the container was unsubscribed | ||
*/ | ||
public boolean replace(Subscription next) { | ||
for (;;) { | ||
Subscription current = get(); | ||
|
||
if (current == Unsubscribed.INSTANCE) { | ||
if (next != null) { | ||
next.unsubscribe(); | ||
} | ||
return false; | ||
} | ||
|
||
if (compareAndSet(current, next)) { | ||
return true; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Atomically tries to set the contained Subscription to the provided next value and unsubscribes | ||
* the previous value or unsubscribes the next value if this container is unsubscribed. | ||
* <p> | ||
* Unlike {@link #update(Subscription)}, this doesn't retry if the replace failed | ||
* because a concurrent operation changed the underlying contained object. | ||
* @param next the next Subscription to contain, may be null | ||
* @return true if the update succeded, false if the container was unsubscribed | ||
*/ | ||
public boolean updateWeak(Subscription next) { | ||
Subscription current = get(); | ||
if (current == Unsubscribed.INSTANCE) { | ||
if (next != null) { | ||
next.unsubscribe(); | ||
} | ||
return false; | ||
} | ||
if (compareAndSet(current, next)) { | ||
return true; | ||
} | ||
|
||
current = get(); | ||
|
||
if (next != null) { | ||
next.unsubscribe(); | ||
} | ||
return current == Unsubscribed.INSTANCE; | ||
} | ||
|
||
/** | ||
* Atomically tries to replace the contained Subscription to the provided next value but | ||
* does not unsubscribe the previous value or unsubscribes the next value if this container | ||
* is unsubscribed. | ||
* <p> | ||
* Unlike {@link #replace(Subscription)}, this doesn't retry if the replace failed | ||
* because a concurrent operation changed the underlying contained object. | ||
* @param next the next Subscription to contain, may be null | ||
* @return true if the update succeded, false if the container was unsubscribed | ||
*/ | ||
public boolean replaceWeak(Subscription next) { | ||
Subscription current = get(); | ||
if (current == Unsubscribed.INSTANCE) { | ||
if (next != null) { | ||
next.unsubscribe(); | ||
} | ||
return false; | ||
} | ||
if (compareAndSet(current, next)) { | ||
return true; | ||
} | ||
|
||
current = get(); | ||
if (current == Unsubscribed.INSTANCE) { | ||
if (next != null) { | ||
next.unsubscribe(); | ||
} | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
public void unsubscribe() { | ||
Subscription current = get(); | ||
if (current != Unsubscribed.INSTANCE) { | ||
current = getAndSet(Unsubscribed.INSTANCE); | ||
if (current != null && current != Unsubscribed.INSTANCE) { | ||
current.unsubscribe(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public boolean isUnsubscribed() { | ||
return get() == Unsubscribed.INSTANCE; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/** | ||
* Copyright 2016 Netflix, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package rx.internal.subscriptions; | ||
|
||
import rx.Subscription; | ||
|
||
/** | ||
* Represents an unsubscribed Subscription via a singleton; don't leak it! | ||
*/ | ||
public enum Unsubscribed implements Subscription { | ||
INSTANCE; | ||
|
||
@Override | ||
public boolean isUnsubscribed() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public void unsubscribe() { | ||
// deliberately ignored | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: do we really need this for internal classes?