All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.conversantmedia.util.concurrent.AtomicSequence Maven / Gradle / Ivy

There is a newer version: 1.2.21
Show newest version
package com.conversantmedia.util.concurrent;

/*
 * #%L
 * Conversant Disruptor
 * ~~
 * Conversantmedia.com © 2016, Conversant, Inc. Conversant® is a trademark of Conversant, 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.
 * #L%
 */

/**
 * This implements the CAS approach to lock-free synchronization, in
 * other words a sequence of atomic changes.  Each change is represented by an
 * integer sequence number.  Each sequence number may represent a single atomic
 * change for a single thread.  All other threads, who fail to acquire permission
 * to update the sequence must obtain another sequence number and try again.
 *
 * If the call to update succeeds, the the caller must call commit to notify other
 * threads that they are finished modifying the sequence.  Otherwise deadlock will occur.
 *
 * Atomic means that only one change per sequence number is possible.  And that changes
 * to numerically lower numbers are guaranteed to occur prior to changes to numerically higher
 * sequence numbers.
 *
 * Unlike synchronization, this mechanism does not include a fence operation.    No thread state
 * is synchronized by this call.    If your usage requires a fence that should be implemented with
 * volatile variables.
 *
 * Its possible for the sequence to flip negative, over hundreds of years or with incredibly fast hardware
 * this would have no impact on the correctness of the atomic sequence.   However, the best practice for code of this nature is
 * to make only relative comparison,   sequence1 - sequence2 {@literal >} 0, rather than sequence1 {@literal >} sequence2
 *
 *
 * The general strategy is as follows:
 *
 * 

 * for(;;) {
 *     long lock = sequence.get();
 *     // any preliminary checking (capacity, etc. can be done here
 *     // the next call ensures that no other thread has modified the sequence
 *     // while we work
 *     if(sequence.update(lock)) {
 *          try {
 *              // update something atomically here
 *              return;
 *          } finally {
 *              sequence.commit();
 *          }
 *     }
 * }
 * 
* * * Created by jcairns on 9/24/14. */ public final class AtomicSequence { private final PaddedAtomicLong cursor = new PaddedAtomicLong(0L); private final PaddedAtomicLong sequence = new PaddedAtomicLong(0L); // Locally (L1) cached value of the sequence // try to use the value in this cores L1 cache whenever possible // rather than reading from memory every time private final PaddedLong sequenceCache = new PaddedLong(0L); /** * @return long - the current sequence */ public long get() { return sequenceCache.value; } /** * force a fenced read of the sequence, only required if the sequence is known out of date * * @return long - sequence number */ public long getAtomic() { return sequenceCache.value = sequence.get(); } /** * * @param sequence - input sequence number * @return boolean - true if its safe to write the transaction for the given sequence */ public boolean update(final long sequence) { if(cursor.compareAndSet(sequence, sequence+1)) { return true; } // must read the sequence cache from memory as it has // been modified by another thread sequenceCache.value = this.sequence.get(); return false; } /** * commit the change to the sequence */ public void commit() { sequence.lazySet(cursor.get()); sequenceCache.value = sequence.get(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy