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

com.hazelcast.internal.util.counters.SwCounter Maven / Gradle / Ivy

/*
 * Copyright (c) 2008-2018, Hazelcast, Inc. All Rights Reserved.
 *
 * 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 com.hazelcast.internal.util.counters;

import com.hazelcast.internal.memory.GlobalMemoryAccessorRegistry;

import java.lang.reflect.Field;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

import static com.hazelcast.internal.memory.GlobalMemoryAccessorRegistry.MEM;
import static com.hazelcast.util.EmptyStatement.ignore;
import static java.util.concurrent.atomic.AtomicLongFieldUpdater.newUpdater;

/**
 * A {@link Counter} that is made to be used by a single writing thread.
 * 

* It makes use of the lazySet to provide a lower overhead than a volatile write on X86 systems. * The volatile write requires waiting for the store buffer to be drained which isn't needed for the lazySet. *

* This counter does not provide padding to prevent false sharing. *

* One might wonder why not use the AtomicLong.inc. The problem here is that AtomicLong requires a full fence, * so there is waiting for store and load buffers to be drained. This is more expensive. *

* One might also wonder why not use the following: *

 *     atomicLong.lazySet(atomicLong.get()+1)
 * 
* This causes a lot of syntactic noise due to lack of abstraction. * A counter.inc() gives a better clue what the intent is. */ public abstract class SwCounter implements Counter { private SwCounter() { } /** * Creates a new SwCounter with 0 as initial value. * * @return the created SwCounter, set to zero. */ public static SwCounter newSwCounter() { return newSwCounter(0); } /** * Creates a new SwCounter with the given initial value. * * @param initialValue the initial value for the SwCounter. * @return the created SwCounter. */ public static SwCounter newSwCounter(long initialValue) { return GlobalMemoryAccessorRegistry.MEM_AVAILABLE ? new UnsafeSwCounter(initialValue) : new SafeSwCounter(initialValue); } /** * The UnsafeSwCounter relies on the same {@link sun.misc.Unsafe#putOrderedLong(Object, long, long)} as the * {@link AtomicLongFieldUpdater#lazySet(Object, long)} but it removes all kinds of checks. *

* For the AtomicLongFieldUpdater, these checks are needed since an arbitrary object can be passed to the * lazySet method and that needs to be verified. In our case we always pass the UnsafeSwCounter instance so * there is no need for these checks. */ static final class UnsafeSwCounter extends SwCounter { private static final long OFFSET; static { Field field = null; try { field = UnsafeSwCounter.class.getDeclaredField("value"); } catch (NoSuchFieldException ignore) { ignore(ignore); } OFFSET = MEM.objectFieldOffset(field); } private long localValue; private volatile long value; protected UnsafeSwCounter(long initialValue) { this.value = initialValue; } @Override @SuppressWarnings("checkstyle:innerassignment") public long inc() { long newLocalValue = localValue += 1; MEM.putOrderedLong(this, OFFSET, newLocalValue); return newLocalValue; } @Override @SuppressWarnings("checkstyle:innerassignment") public long inc(long amount) { long newLocalValue = localValue += amount; MEM.putOrderedLong(this, OFFSET, newLocalValue); return newLocalValue; } @Override public long get() { return value; } @Override public String toString() { return "Counter{value=" + value + '}'; } } /** * Makes use of the AtomicLongFieldUpdater.lazySet. */ static final class SafeSwCounter extends SwCounter { private static final AtomicLongFieldUpdater COUNTER = newUpdater(SafeSwCounter.class, "value"); private volatile long value; protected SafeSwCounter(long initialValue) { this.value = initialValue; } @Override public long inc() { final long newValue = value + 1; COUNTER.lazySet(this, newValue); return newValue; } @Override public long inc(long amount) { final long newValue = value + amount; COUNTER.lazySet(this, newValue); return newValue; } @Override public long get() { return value; } @Override public String toString() { return "Counter{value=" + value + '}'; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy