This commit is contained in:
Alejandro Murillo 2016-07-18 09:38:08 -07:00
commit 50862707c8
337 changed files with 18107 additions and 5335 deletions

View File

@ -369,3 +369,4 @@ d53037a90c441cb528dc41c30827985de0e67c62 jdk-9+123
2a5697a98620c4f40e4a1a71478464399b8878de jdk-9+124
3aa52182b3ad7c5b3a61cf05a59dd07e4c5884e5 jdk-9+125
03e7b2c5ae345be3caf981d76ceb3efe5ff447f8 jdk-9+126
8e45018bde9de4ad15b972ae62874bba52dba2d5 jdk-9+127

View File

@ -369,3 +369,4 @@ cae471d3b87783e0a3deea658e1e1c84b2485b6c jdk-9+121
f80c841ae2545eaf9acd2724bccc305d98cefbe2 jdk-9+124
9aa7d40f3a453f51e47f4c1b19eff5740a74a9f8 jdk-9+125
3a58466296d36944454756ef01e7513ac5e14a16 jdk-9+126
8fa686245bd2a072ece3392743460030f0854520 jdk-9+127

View File

@ -369,3 +369,4 @@ e33a34cc551907617d8129c4faaf1a5a7e61d21c jdk-9+123
45121d5afb9d5bfadab75378572ad96832e0809e jdk-9+124
1d48e67d1b91eb9f72e49e69a4021edb85e357fc jdk-9+125
c7f5ba08fcd4b8416e62c21229f9a07c95498919 jdk-9+126
8fab452b6f4710762ba1d8e55fd62db00b1355fe jdk-9+127

View File

@ -529,3 +529,4 @@ af6b4ad908e732d23021f12e8322b204433d5cf6 jdk-9+122
479631362b4930be985245ea063d87d821a472eb jdk-9+124
bb640b49741af3f57f9994129934c46fc173219f jdk-9+125
adc8c84b7cf8c540d920182f78a2bc982366432a jdk-9+126
352357128f602dcf0426b1cbe011a4685a4d9f97 jdk-9+127

View File

@ -45,7 +45,8 @@ ifeq ($(call check-jvm-feature, dtrace), true)
$(DTRACE_GENSRC_DIR)/%.h: $(DTRACE_SOURCE_DIR)/%.d
$(call LogInfo, Generating dtrace header file $(@F))
$(call MakeDir, $(@D) $(DTRACE_SUPPORT_DIR))
$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d)
$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
( $(CC) -E $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d ) )
$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -h -o $@ -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
# Process all .d files in DTRACE_SOURCE_DIR. They are:

View File

@ -68,7 +68,7 @@ ifeq ($(call check-jvm-feature, dtrace), true)
$1: $$(BUILD_DTRACE_GEN_OFFSETS)
$$(call LogInfo, Generating dtrace $2 file $$(@F))
$$(call MakeDir, $$(@D))
$$(call ExecuteWithLog, $$@, $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@)
$$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) )
TARGETS += $1
endef

View File

@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package com.sun.hotspot.tools.compiler;

View File

@ -501,13 +501,26 @@ ClassLoaderData::~ClassLoaderData() {
}
}
/**
* Returns true if this class loader data is for the platform class loader.
*/
// Returns true if this class loader data is for the system class loader.
bool ClassLoaderData::is_system_class_loader_data() const {
return SystemDictionary::is_system_class_loader(class_loader());
}
// Returns true if this class loader data is for the platform class loader.
bool ClassLoaderData::is_platform_class_loader_data() const {
return SystemDictionary::is_platform_class_loader(class_loader());
}
// Returns true if this class loader data is one of the 3 builtin
// (boot, application/system or platform) class loaders. Note, the
// builtin loaders are not freed by a GC.
bool ClassLoaderData::is_builtin_class_loader_data() const {
Handle classLoaderHandle = class_loader();
return (is_the_null_class_loader_data() ||
SystemDictionary::is_system_class_loader(classLoaderHandle) ||
SystemDictionary::is_platform_class_loader(classLoaderHandle));
}
Metaspace* ClassLoaderData::metaspace_non_null() {
assert(!DumpSharedSpaces, "wrong metaspace!");
// If the metaspace has not been allocated, create a new one. Might want
@ -957,12 +970,6 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
data = _head;
while (data != NULL) {
if (data->is_alive(is_alive_closure)) {
if (data->packages_defined()) {
data->packages()->purge_all_package_exports();
}
if (data->modules_defined()) {
data->modules()->purge_all_module_reads();
}
// clean metaspace
if (walk_all_metadata) {
data->classes_do(InstanceKlass::purge_previous_versions);
@ -990,6 +997,23 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
}
if (seen_dead_loader) {
// Walk a ModuleEntry's reads and a PackageEntry's exports lists
// to determine if there are modules on those lists that are now
// dead and should be removed. A module's life cycle is equivalent
// to its defining class loader's life cycle. Since a module is
// considered dead if its class loader is dead, these walks must
// occur after each class loader's aliveness is determined.
data = _head;
while (data != NULL) {
if (data->packages_defined()) {
data->packages()->purge_all_package_exports();
}
if (data->modules_defined()) {
data->modules()->purge_all_module_reads();
}
data = data->next();
}
post_class_unload_events();
}

View File

@ -270,7 +270,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
bool is_the_null_class_loader_data() const {
return this == _the_null_class_loader_data;
}
bool is_system_class_loader_data() const;
bool is_platform_class_loader_data() const;
bool is_builtin_class_loader_data() const;
// The Metaspace is created lazily so may be NULL. This
// method will allocate a Metaspace if needed.

View File

@ -248,7 +248,7 @@ inline void SimpleCompactHashtable::iterate(const I& iterator) {
} else {
u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]);
while (entry < entry_max) {
iterator.do_value(_base_address, entry[0]);
iterator.do_value(_base_address, entry[1]);
entry += 2;
}
}

View File

@ -40,7 +40,6 @@
ModuleEntry* ModuleEntryTable::_javabase_module = NULL;
void ModuleEntry::set_location(Symbol* location) {
if (_location != NULL) {
// _location symbol's refcounts are managed by ModuleEntry,
@ -115,10 +114,35 @@ void ModuleEntry::add_read(ModuleEntry* m) {
// Lazily create a module's reads list
_reads = new (ResourceObj::C_HEAP, mtModule)GrowableArray<ModuleEntry*>(MODULE_READS_SIZE, true);
}
// Determine, based on this newly established read edge to module m,
// if this module's read list should be walked at a GC safepoint.
set_read_walk_required(m->loader_data());
// Establish readability to module m
_reads->append_if_missing(m);
}
}
// If the module's loader, that a read edge is being established to, is
// not the same loader as this module's and is not one of the 3 builtin
// class loaders, then this module's reads list must be walked at GC
// safepoint. Modules have the same life cycle as their defining class
// loaders and should be removed if dead.
void ModuleEntry::set_read_walk_required(ClassLoaderData* m_loader_data) {
assert_locked_or_safepoint(Module_lock);
if (!_must_walk_reads &&
loader_data() != m_loader_data &&
!m_loader_data->is_builtin_class_loader_data()) {
_must_walk_reads = true;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
log_trace(modules)("ModuleEntry::set_read_walk_required(): module %s reads list must be walked",
(name() != NULL) ? name()->as_C_string() : UNNAMED_MODULE);
}
}
}
bool ModuleEntry::has_reads() const {
assert_locked_or_safepoint(Module_lock);
return ((_reads != NULL) && !_reads->is_empty());
@ -127,14 +151,28 @@ bool ModuleEntry::has_reads() const {
// Purge dead module entries out of reads list.
void ModuleEntry::purge_reads() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
if (has_reads()) {
if (_must_walk_reads && has_reads()) {
// This module's _must_walk_reads flag will be reset based
// on the remaining live modules on the reads list.
_must_walk_reads = false;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
log_trace(modules)("ModuleEntry::purge_reads(): module %s reads list being walked",
(name() != NULL) ? name()->as_C_string() : UNNAMED_MODULE);
}
// Go backwards because this removes entries that are dead.
int len = _reads->length();
for (int idx = len - 1; idx >= 0; idx--) {
ModuleEntry* module_idx = _reads->at(idx);
ClassLoaderData* cld = module_idx->loader();
if (cld->is_unloading()) {
ClassLoaderData* cld_idx = module_idx->loader_data();
if (cld_idx->is_unloading()) {
_reads->delete_at(idx);
} else {
// Update the need to walk this module's reads based on live modules
set_read_walk_required(cld_idx);
}
}
}
@ -248,7 +286,7 @@ ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle
entry->set_module(loader_data->add_handle(module_handle));
}
entry->set_loader(loader_data);
entry->set_loader_data(loader_data);
entry->set_version(version);
entry->set_location(location);
@ -375,11 +413,11 @@ void ModuleEntryTable::print(outputStream* st) {
void ModuleEntry::print(outputStream* st) {
ResourceMark rm;
st->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT,
st->print_cr("entry " PTR_FORMAT " name %s module " PTR_FORMAT " loader %s version %s location %s strict %s next " PTR_FORMAT,
p2i(this),
name() == NULL ? UNNAMED_MODULE : name()->as_C_string(),
p2i(module()),
loader()->loader_name(),
loader_data()->loader_name(),
version() != NULL ? version()->as_C_string() : "NULL",
location() != NULL ? location()->as_C_string() : "NULL",
BOOL_TO_STR(!can_read_all_unnamed()), p2i(next()));
@ -401,5 +439,5 @@ void ModuleEntryTable::verify() {
}
void ModuleEntry::verify() {
guarantee(loader() != NULL, "A module entry must be associated with a loader.");
guarantee(loader_data() != NULL, "A module entry must be associated with a loader.");
}

View File

@ -43,6 +43,7 @@ class ModuleClosure;
// It contains:
// - Symbol* containing the module's name.
// - pointer to the java.lang.reflect.Module for this module.
// - pointer to the java.security.ProtectionDomain shared by classes defined to this module.
// - ClassLoaderData*, class loader of this module.
// - a growable array containg other module entries that this module can read.
// - a flag indicating if this module can read all unnamed modules.
@ -54,56 +55,58 @@ private:
jobject _module; // java.lang.reflect.Module
jobject _pd; // java.security.ProtectionDomain, cached
// for shared classes from this module
ClassLoaderData* _loader;
ClassLoaderData* _loader_data;
GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
Symbol* _version; // module version number
Symbol* _location; // module location
bool _can_read_all_unnamed;
bool _has_default_read_edges; // JVMTI redefine/retransform support
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
TRACE_DEFINE_TRACE_ID_FIELD;
enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read.
public:
void init() {
_module = NULL;
_loader = NULL;
_loader_data = NULL;
_pd = NULL;
_reads = NULL;
_version = NULL;
_location = NULL;
_can_read_all_unnamed = false;
_has_default_read_edges = false;
_must_walk_reads = false;
}
Symbol* name() const { return literal(); }
void set_name(Symbol* n) { set_literal(n); }
Symbol* name() const { return literal(); }
void set_name(Symbol* n) { set_literal(n); }
jobject module() const { return _module; }
void set_module(jobject j) { _module = j; }
jobject module() const { return _module; }
void set_module(jobject j) { _module = j; }
// The shared ProtectionDomain reference is set once the VM loads a shared class
// originated from the current Module. The referenced ProtectionDomain object is
// created by the ClassLoader when loading a class (shared or non-shared) from the
// Module for the first time. This ProtectionDomain object is used for all
// classes from the Module loaded by the same ClassLoader.
Handle shared_protection_domain();
void set_shared_protection_domain(ClassLoaderData *loader_data,
Handle pd);
Handle shared_protection_domain();
void set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd);
ClassLoaderData* loader() const { return _loader; }
void set_loader(ClassLoaderData* l) { _loader = l; }
ClassLoaderData* loader_data() const { return _loader_data; }
void set_loader_data(ClassLoaderData* l) { _loader_data = l; }
Symbol* version() const { return _version; }
void set_version(Symbol* version);
Symbol* version() const { return _version; }
void set_version(Symbol* version);
Symbol* location() const { return _location; }
void set_location(Symbol* location);
Symbol* location() const { return _location; }
void set_location(Symbol* location);
bool can_read(ModuleEntry* m) const;
bool has_reads() const;
void add_read(ModuleEntry* m);
bool can_read(ModuleEntry* m) const;
bool has_reads() const;
void add_read(ModuleEntry* m);
void set_read_walk_required(ClassLoaderData* m_loader_data);
bool is_named() const { return (literal() != NULL); }
bool is_named() const { return (name() != NULL); }
bool can_read_all_unnamed() const {
assert(is_named() || _can_read_all_unnamed == true,
@ -178,7 +181,7 @@ private:
ModuleEntry* _unnamed_module;
ModuleEntry* new_entry(unsigned int hash, Handle module_handle, Symbol* name, Symbol* version,
Symbol* location, ClassLoaderData* class_loader);
Symbol* location, ClassLoaderData* loader_data);
void add_entry(int index, ModuleEntry* new_entry);
int entry_size() const { return BasicHashtable<mtModule>::entry_size(); }

View File

@ -113,7 +113,7 @@ static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring packag
const char *package_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(package));
if (package_name == NULL) return NULL;
TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK_NULL);
PackageEntryTable* package_entry_table = module_entry->loader()->packages();
PackageEntryTable* package_entry_table = module_entry->loader_data()->packages();
assert(package_entry_table != NULL, "Unexpected null package entry table");
return package_entry_table->lookup_only(pkg_symbol);
}
@ -868,7 +868,7 @@ void Modules::add_module_package(jobject module, jstring package, TRAPS) {
package_name, module_entry->name()->as_C_string());
TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK);
PackageEntryTable* package_table = module_entry->loader()->packages();
PackageEntryTable* package_table = module_entry->loader_data()->packages();
assert(package_table != NULL, "Missing package_table");
bool pkg_exists = false;

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
@ -53,12 +54,40 @@ void PackageEntry::add_qexport(ModuleEntry* m) {
if (!has_qual_exports_list()) {
// Lazily create a package's qualified exports list.
// Initial size is small, do not anticipate export lists to be large.
_qualified_exports =
new (ResourceObj::C_HEAP, mtModule) GrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, true);
_qualified_exports = new (ResourceObj::C_HEAP, mtModule) GrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, true);
}
// Determine, based on this newly established export to module m,
// if this package's export list should be walked at a GC safepoint.
set_export_walk_required(m->loader_data());
// Establish exportability to module m
_qualified_exports->append_if_missing(m);
}
// If the module's loader, that an export is being established to, is
// not the same loader as this module's and is not one of the 3 builtin
// class loaders, then this package's export list must be walked at GC
// safepoint. Modules have the same life cycle as their defining class
// loaders and should be removed if dead.
void PackageEntry::set_export_walk_required(ClassLoaderData* m_loader_data) {
assert_locked_or_safepoint(Module_lock);
ModuleEntry* this_pkg_mod = module();
if (!_must_walk_exports &&
(this_pkg_mod == NULL || this_pkg_mod->loader_data() != m_loader_data) &&
!m_loader_data->is_builtin_class_loader_data()) {
_must_walk_exports = true;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
assert(name() != NULL, "PackageEntry without a valid name");
log_trace(modules)("PackageEntry::set_export_walk_required(): package %s defined in module %s, exports list must be walked",
name()->as_C_string(),
(this_pkg_mod == NULL || this_pkg_mod->name() == NULL) ?
UNNAMED_MODULE : this_pkg_mod->name()->as_C_string());
}
}
}
// Set the package's exported states based on the value of the ModuleEntry.
void PackageEntry::set_exported(ModuleEntry* m) {
MutexLocker m1(Module_lock);
@ -96,14 +125,34 @@ void PackageEntry::set_is_exported_allUnnamed() {
// Remove dead module entries within the package's exported list.
void PackageEntry::purge_qualified_exports() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
if (_qualified_exports != NULL) {
if (_must_walk_exports &&
_qualified_exports != NULL &&
!_qualified_exports->is_empty()) {
ModuleEntry* pkg_module = module();
// This package's _must_walk_exports flag will be reset based
// on the remaining live modules on the exports list.
_must_walk_exports = false;
if (log_is_enabled(Trace, modules)) {
ResourceMark rm;
assert(name() != NULL, "PackageEntry without a valid name");
ModuleEntry* pkg_mod = module();
log_trace(modules)("PackageEntry::purge_qualified_exports(): package %s defined in module %s, exports list being walked",
name()->as_C_string(),
(pkg_mod == NULL || pkg_mod->name() == NULL) ? UNNAMED_MODULE : pkg_mod->name()->as_C_string());
}
// Go backwards because this removes entries that are dead.
int len = _qualified_exports->length();
for (int idx = len - 1; idx >= 0; idx--) {
ModuleEntry* module_idx = _qualified_exports->at(idx);
ClassLoaderData* cld = module_idx->loader();
if (cld->is_unloading()) {
ClassLoaderData* cld_idx = module_idx->loader_data();
if (cld_idx->is_unloading()) {
_qualified_exports->delete_at(idx);
} else {
// Update the need to walk this package's exports based on live modules
set_export_walk_required(cld_idx);
}
}
}
@ -297,8 +346,8 @@ void PackageEntryTable::print(outputStream* st) {
void PackageEntry::print(outputStream* st) {
ResourceMark rm;
st->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index "
INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next "PTR_FORMAT,
st->print_cr("package entry " PTR_FORMAT " name %s module %s classpath_index "
INT32_FORMAT " is_exported_unqualified %d is_exported_allUnnamed %d " "next " PTR_FORMAT,
p2i(this), name()->as_C_string(),
(module()->is_named() ? module()->name()->as_C_string() : UNNAMED_MODULE),
_classpath_index, _is_exported_unqualified, _is_exported_allUnnamed, p2i(next()));

View File

@ -69,6 +69,7 @@ private:
s2 _classpath_index;
bool _is_exported_unqualified;
bool _is_exported_allUnnamed;
bool _must_walk_exports;
GrowableArray<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
GrowableArray<ModuleEntry*>* _qualified_exports;
TRACE_DEFINE_TRACE_ID_FIELD;
@ -82,6 +83,7 @@ public:
_classpath_index = -1;
_is_exported_unqualified = false;
_is_exported_allUnnamed = false;
_must_walk_exports = false;
_exported_pending_delete = NULL;
_qualified_exports = NULL;
}
@ -147,6 +149,7 @@ public:
// add the module to the package's qualified exports
void add_qexport(ModuleEntry* m);
void set_export_walk_required(ClassLoaderData* m_loader_data);
PackageEntry* next() const {
return (PackageEntry*)HashtableEntry<Symbol*, mtModule>::next();

View File

@ -175,9 +175,18 @@ bool SystemDictionary::is_parallelDefine(Handle class_loader) {
return false;
}
/**
* Returns true if the passed class loader is the platform class loader.
*/
// Returns true if the passed class loader is the builtin application class loader
// or a custom system class loader. A customer system class loader can be
// specified via -Djava.system.class.loader.
bool SystemDictionary::is_system_class_loader(Handle class_loader) {
if (class_loader.is_null()) {
return false;
}
return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() ||
class_loader() == _java_system_loader);
}
// Returns true if the passed class loader is the platform class loader.
bool SystemDictionary::is_platform_class_loader(Handle class_loader) {
if (class_loader.is_null()) {
return false;

View File

@ -660,6 +660,7 @@ public:
static instanceKlassHandle load_shared_class(Symbol* class_name,
Handle class_loader,
TRAPS);
static bool is_system_class_loader(Handle class_loader);
static bool is_platform_class_loader(Handle class_loader);
protected:

View File

@ -48,10 +48,10 @@ void PreservedMarks::restore_and_increment(volatile size_t* const total_size_add
#ifndef PRODUCT
void PreservedMarks::assert_empty() {
assert(_stack.is_empty(), "stack expected to be empty, size = "SIZE_FORMAT,
assert(_stack.is_empty(), "stack expected to be empty, size = " SIZE_FORMAT,
_stack.size());
assert(_stack.cache_size() == 0,
"stack expected to have no cached segments, cache size = "SIZE_FORMAT,
"stack expected to have no cached segments, cache size = " SIZE_FORMAT,
_stack.cache_size());
}
#endif // ndef PRODUCT

View File

@ -419,21 +419,20 @@ void Rewriter::scan_method(Method* method, bool reverse, bool* invokespecial_err
InstanceKlass* klass = method->method_holder();
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
constantPoolHandle cp(method->constants());
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
if (klass->name() == ref_class_name) {
Symbol* field_name = cp->name_ref_at(bc_index);
Symbol* field_sig = cp->signature_ref_at(bc_index);
fieldDescriptor fd;
klass->find_field(field_name, field_sig, &fd);
if (fd.access_flags().is_final()) {
if (fd.access_flags().is_static()) {
assert(c == Bytecodes::_putstatic, "must be putstatic");
if (!method->is_static_initializer()) {
fd.set_has_initialized_final_update(true);
}
} else {
assert(c == Bytecodes::_putfield, "must be putfield");
if (!method->is_object_initializer()) {
fd.set_has_initialized_final_update(true);
}

View File

@ -584,27 +584,26 @@ static bool verify_special_jvm_flags() {
// Parses a size specification string.
bool Arguments::atojulong(const char *s, julong* result) {
julong n = 0;
int args_read = 0;
bool is_hex = false;
// Skip leading 0[xX] for hexadecimal
if (*s =='0' && (*(s+1) == 'x' || *(s+1) == 'X')) {
s += 2;
is_hex = true;
args_read = sscanf(s, JULONG_FORMAT_X, &n);
} else {
args_read = sscanf(s, JULONG_FORMAT, &n);
}
if (args_read != 1) {
// First char must be a digit. Don't allow negative numbers or leading spaces.
if (!isdigit(*s)) {
return false;
}
while (*s != '\0' && (isdigit(*s) || (is_hex && isxdigit(*s)))) {
s++;
}
// 4705540: illegal if more characters are found after the first non-digit
if (strlen(s) > 1) {
bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'));
char* remainder;
errno = 0;
n = strtoull(s, &remainder, (is_hex ? 16 : 10));
if (errno != 0) {
return false;
}
switch (*s) {
// Fail if no number was read at all or if the remainder contains more than a single non-digit character.
if (remainder == s || strlen(remainder) > 1) {
return false;
}
switch (*remainder) {
case 'T': case 't':
*result = n * G * K;
// Check for overflow.

View File

@ -205,16 +205,39 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt,
static void print_oom_reasons(outputStream* st) {
st->print_cr("# Possible reasons:");
st->print_cr("# The system is out of physical RAM or swap space");
st->print_cr("# In 32 bit mode, the process size limit was hit");
if (UseCompressedOops) {
st->print_cr("# The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap");
}
if (LogBytesPerWord == 2) {
st->print_cr("# In 32 bit mode, the process size limit was hit");
}
st->print_cr("# Possible solutions:");
st->print_cr("# Reduce memory load on the system");
st->print_cr("# Increase physical memory or swap space");
st->print_cr("# Check if swap backing store is full");
st->print_cr("# Use 64 bit Java on a 64 bit OS");
if (LogBytesPerWord == 2) {
st->print_cr("# Use 64 bit Java on a 64 bit OS");
}
st->print_cr("# Decrease Java heap size (-Xmx/-Xms)");
st->print_cr("# Decrease number of Java threads");
st->print_cr("# Decrease Java thread stack sizes (-Xss)");
st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize=");
if (UseCompressedOops) {
switch (Universe::narrow_oop_mode()) {
case Universe::UnscaledNarrowOop:
st->print_cr("# JVM is running with Unscaled Compressed Oops mode in which the Java heap is");
st->print_cr("# placed in the first 4GB address space. The Java Heap base address is the");
st->print_cr("# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress");
st->print_cr("# to set the Java Heap base and to place the Java Heap above 4GB virtual address.");
break;
case Universe::ZeroBasedNarrowOop:
st->print_cr("# JVM is running with Zero Based Compressed Oops mode in which the Java heap is");
st->print_cr("# placed in the first 32GB address space. The Java Heap base address is the");
st->print_cr("# maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress");
st->print_cr("# to set the Java Heap base and to place the Java Heap above 32GB virtual address.");
break;
}
}
st->print_cr("# This output file may be truncated or incomplete.");
}

View File

@ -395,6 +395,17 @@ hotspot_jprt = \
:hotspot_fast_gc_gcold \
:hotspot_fast_runtime \
:hotspot_fast_serviceability
hotspot_runtime_tier2 = \
runtime/ \
serviceability/ \
-:hotspot_fast_runtime \
-:hotspot_fast_serviceability \
-:hotspot_runtime_tier2_platform_agnostic
hotspot_runtime_tier2_platform_agnostic = \
runtime/SelectionResolution \
-:hotspot_fast_runtime
#All tests that depends on nashorn extension.
#

View File

@ -0,0 +1,234 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package gc.g1.humongousObjects;
import jdk.test.lib.Utils;
import sun.hotspot.WhiteBox;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
/**
* @test TestNoAllocationsInHRegions
* @summary Checks that no additional allocations are made in humongous regions
* @requires vm.gc.G1
* @library /testlibrary /test/lib /
* @modules java.management java.base/jdk.internal.misc
* @build sun.hotspot.WhiteBox
* gc.testlibrary.Helpers
* gc.g1.humongousObjects.TestNoAllocationsInHRegions
*
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
*
* @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0
* -Xlog:gc=trace:file=TestNoAllocationsInHRegions10.log
* gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 10
*
* @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0
* -Xlog:gc=trace:file=TestNoAllocationsInHRegions50.log
* gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 50
*
* @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xms200m -Xmx200m -XX:MaxTenuringThreshold=0
* -Xlog:gc=trace:file=TestNoAllocationsInHRegions70.log
* gc.g1.humongousObjects.TestNoAllocationsInHRegions 30 70
*/
public class TestNoAllocationsInHRegions {
private static final WhiteBox WB = WhiteBox.getWhiteBox();
private static final Random RND = Utils.getRandomInstance();
private static final int G1_REGION_SIZE = WB.g1RegionSize();
private static final int[] HUMONGOUS_SIZES = {G1_REGION_SIZE / 2, G1_REGION_SIZE + 1, G1_REGION_SIZE * 2 + 1};
private static final int ALLOC_THREAD_COUNT = 5;
// We fill specified part of heap with humongous objects - we need public static to prevent escape analysis to
// collect this field
public static LinkedList<byte[]> humongousAllocations = new LinkedList<>();
private static volatile boolean shouldStop = false;
private static volatile Error error = null;
static class Allocator implements Runnable {
private final List<byte[]> liveObjects = new LinkedList<>();
private int usedMemory = 0;
public final Runnable[] actions;
/**
* Maximum size of simple allocation
*/
private static final int MAX_ALLOCATION_SIZE = (int) (G1_REGION_SIZE / 2 * 0.9);
/**
* Maximum size of dead (i.e. one which is made unreachable right after allocation) object
*/
private static final int DEAD_OBJECT_MAX_SIZE = G1_REGION_SIZE / 10;
public Allocator(int maxAllocationMemory) {
actions = new Runnable[]{
// Allocation
() -> {
if (maxAllocationMemory - usedMemory != 0) {
int arraySize = RND.nextInt(Math.min(maxAllocationMemory - usedMemory,
MAX_ALLOCATION_SIZE));
if (arraySize != 0) {
byte[] allocation = new byte[arraySize];
liveObjects.add(allocation);
usedMemory += arraySize;
// Sanity check
if (WB.g1IsHumongous(allocation)) {
String errorMessage = String.format("Test Bug: Byte array of size"
+ " %d is expected to be non-humongous but it is humongous",
allocation.length);
System.out.println(errorMessage);
error = new Error(errorMessage);
shouldStop = true;
}
// Test check
if (WB.g1BelongsToHumongousRegion(WB.getObjectAddress(allocation))) {
String errorMessage = String.format("Non-humongous allocation of byte array of "
+ "length %d and size %d with address %d was made in Humongous Region",
allocation.length, WB.getObjectSize(allocation),
WB.getObjectAddress(allocation));
System.out.println(errorMessage);
error = new Error(errorMessage);
shouldStop = true;
}
}
}
},
// Deallocation
() -> {
if (liveObjects.size() != 0) {
int elementNum = RND.nextInt(liveObjects.size());
int shouldFree = liveObjects.get(elementNum).length;
liveObjects.remove(elementNum);
usedMemory -= shouldFree;
}
},
// Dead object allocation
() -> {
int size = RND.nextInt(DEAD_OBJECT_MAX_SIZE);
byte[] deadObject = new byte[size];
},
// Check
() -> {
List<byte[]> wrongHumongousAllocations = liveObjects.stream()
.filter(WB::g1IsHumongous)
.collect(Collectors.toList());
if (wrongHumongousAllocations.size() > 0) {
wrongHumongousAllocations.stream().forEach(a ->
System.out.format("Non-humongous allocation of byte array of length %d and"
+ " size %d with address %d was made in Humongous Region",
a.length, WB.getObjectSize(a), WB.getObjectAddress(a)));
error = new Error("Some non-humongous allocations were made to humongous region");
shouldStop = true;
}
}
};
}
@Override
public void run() {
while (!shouldStop) {
actions[RND.nextInt(actions.length)].run();
Thread.yield();
}
}
}
public static void main(String[] args) {
if (args.length != 2) {
throw new Error("Test Bug: Expected duration (in seconds) and percent of allocated regions were not "
+ "provided as command line argument");
}
// test duration
long duration = Integer.parseInt(args[0]) * 1000L;
// part of heap preallocated with humongous objects (in percents)
int percentOfAllocatedHeap = Integer.parseInt(args[1]);
long startTime = System.currentTimeMillis();
long initialFreeRegionsCount = WB.g1NumFreeRegions();
int regionsToAllocate = (int) ((double) initialFreeRegionsCount / 100.0 * percentOfAllocatedHeap);
long freeRegionLeft = initialFreeRegionsCount - regionsToAllocate;
System.out.println("Regions to allocate: " + regionsToAllocate + "; regions to left free: " + freeRegionLeft);
int maxMemoryPerAllocThread = (int) ((Runtime.getRuntime().freeMemory() / 100.0
* (100 - percentOfAllocatedHeap)) / ALLOC_THREAD_COUNT * 0.5);
System.out.println("Using " + maxMemoryPerAllocThread / 1024 + "KB for each of " + ALLOC_THREAD_COUNT
+ " allocation threads");
while (WB.g1NumFreeRegions() > freeRegionLeft) {
try {
humongousAllocations.add(new byte[HUMONGOUS_SIZES[RND.nextInt(HUMONGOUS_SIZES.length)]]);
} catch (OutOfMemoryError oom) {
//We got OOM trying to fill heap with humongous objects
//It probably means that heap is fragmented which is strange since the test logic should avoid it
System.out.println("Warning: OOM while allocating humongous objects - it likely means "
+ "that heap is fragmented");
break;
}
}
System.out.println("Initial free regions " + initialFreeRegionsCount + "; Free regions left "
+ WB.g1NumFreeRegions());
LinkedList<Thread> threads = new LinkedList<>();
for (int i = 0; i < ALLOC_THREAD_COUNT; i++) {
threads.add(new Thread(new Allocator(maxMemoryPerAllocThread)));
}
threads.stream().forEach(Thread::start);
while ((System.currentTimeMillis() - startTime < duration) && error == null) {
Thread.yield();
}
shouldStop = true;
System.out.println("Finished test");
if (error != null) {
throw error;
}
}
}

View File

@ -138,6 +138,41 @@ public enum GC {
}
},
MIXED_GC {
@Override
public Runnable get() {
return () -> {
WHITE_BOX.youngGC();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
WHITE_BOX.youngGC();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
WHITE_BOX.g1StartConcMarkCycle();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
WHITE_BOX.youngGC();
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
// Provoking Mixed GC
WHITE_BOX.youngGC();// second evacuation pause will be mixed
Helpers.waitTillCMCFinished(WHITE_BOX, 0);
};
}
public Consumer<ReferenceInfo<Object[]>> getChecker() {
return getCheckerImpl(true, false, true, false);
}
@Override
public List<String> shouldContain() {
return Arrays.asList(GCTokens.WB_INITIATED_CMC);
}
@Override
public List<String> shouldNotContain() {
return Arrays.asList(GCTokens.YOUNG_GC);
}
},
FULL_GC_MEMORY_PRESSURE {
@Override
public Runnable get() {

View File

@ -38,6 +38,9 @@ The test checks that after different type of GC unreachable objects behave as ex
non-humongous and humongous objects are not collected since we make 2 Young GC to promote all
weak references to Old Gen.
6. Mixed GC - weakly referenced non-humongous and humongous objects are collected, softly referenced non-humongous and
humongous objects are not collected.
The test gets gc type as a command line argument.
Then the test allocates object graph in heap (currently testing scenarios are pre-generated and stored in
TestcaseData.getPregeneratedTestcases()) with TestObjectGraphAfterGC::allocateObjectGraph.

View File

@ -66,6 +66,12 @@ import java.util.stream.Collectors;
* sun.hotspot.WhiteBox$WhiteBoxPermission
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=30000 -XX:G1MixedGCLiveThresholdPercent=100 -XX:G1HeapWastePercent=0
* -XX:G1HeapRegionSize=1M -Xlog:gc=info:file=TestObjectGraphAfterGC_MIXED_GC.gc.log -XX:MaxTenuringThreshold=1
* -XX:G1MixedGCCountTarget=1 -XX:G1OldCSetRegionThresholdPercent=100 -XX:SurvivorRatio=1 -XX:InitiatingHeapOccupancyPercent=0
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC MIXED_GC
*
* @run main/othervm -Xms200M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
* -XX:G1HeapRegionSize=1M -Xlog:gc*=debug:file=TestObjectGraphAfterGC_YOUNG_GC.gc.log
* gc.g1.humongousObjects.objectGraphTest.TestObjectGraphAfterGC YOUNG_GC
*

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "runtime/arguments.hpp"
#include "unittest.hpp"
#include "utilities/globalDefinitions.hpp"
TEST(arguments, atojulong) {
char ullong_max[32];
int ret = jio_snprintf(ullong_max, sizeof(ullong_max), JULONG_FORMAT, ULLONG_MAX);
ASSERT_NE(-1, ret);
julong value;
const char* invalid_strings[] = {
"", "-1", "-100", " 1", "2 ", "3 2", "1.0",
"0x4.5", "0x", "0x0x1" "0.001", "4e10", "e"
"K", "M", "G", "1MB", "1KM", "AA", "0B",
"18446744073709551615K", "17179869184G",
"999999999999999999999999999999"
};
for (uint i = 0; i < ARRAY_SIZE(invalid_strings); i++) {
ASSERT_FALSE(Arguments::atojulong(invalid_strings[i], &value))
<< "Invalid string '" << invalid_strings[i] << "' parsed without error.";
}
struct {
const char* str;
julong expected_value;
} valid_strings[] = {
{ "0", 0 },
{ "4711", 4711 },
{ "1K", 1ULL * K },
{ "1k", 1ULL * K },
{ "2M", 2ULL * M },
{ "2m", 2ULL * M },
{ "4G", 4ULL * G },
{ "4g", 4ULL * G },
{ "0K", 0 },
{ ullong_max, ULLONG_MAX },
{ "0xcafebabe", 0xcafebabe },
{ "0XCAFEBABE", 0xcafebabe },
{ "0XCAFEbabe", 0xcafebabe },
{ "0x10K", 0x10 * K }
};
for (uint i = 0; i < ARRAY_SIZE(valid_strings); i++) {
ASSERT_TRUE(Arguments::atojulong(valid_strings[i].str, &value))
<< "Valid string '" << valid_strings[i].str << "' did not parse.";
ASSERT_EQ(valid_strings[i].expected_value, value);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* Recoded in jasm to provoke an ICCE assigning a non-static final field with putstatic.
class Bad {
public static final int i; //rewritten
//rewritten to: public final int i;
static { i = 5; } // putstatic instruction
}
*/
super class Bad
version 53:0
{
// Remove 'static' keyword
public final Field i:I;
Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
static Method "<clinit>":"()V"
stack 1 locals 0
{
iconst_5;
putstatic Field i:"I";
return;
}
} // end Class Bad

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test PutfieldError
* @bug 8160551
* @summary Throw ICCE rather than crashing for nonstatic final field in static initializer
* @compile Bad.jasm
* @run main PutfieldError
*/
public class PutfieldError {
public static void main(java.lang.String[] unused) {
try {
Bad b = new Bad();
System.out.println("Bad.i = " + 5);
throw new RuntimeException("ICCE NOT thrown as expected");
} catch (IncompatibleClassChangeError icce) {
System.out.println("ICCE thrown as expected");
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test SharedStringsDedup
* @summary Test -Xshare:auto with shared strings and -XX:+UseStringDeduplication
* Feature support: G1GC only, compressed oops/kptrs, 64-bit os, not on windows
* @requires (sun.arch.data.model != "32") & (os.family != "windows")
* @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
* @requires vm.gc.G1
* @library /testlibrary
* @modules java.base/jdk.internal.misc
* java.management
* @run main SharedStringsDedup
*/
import jdk.test.lib.*;
import java.io.File;
// The main purpose is to test the interaction between shared strings
// and -XX:+UseStringDeduplication. We run in -Xshare:auto mode so
// we don't need to worry about CDS archive mapping failure (which
// doesn't happen often so it won't impact coverage).
public class SharedStringsDedup {
public static void main(String[] args) throws Exception {
// Dump
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:+UnlockDiagnosticVMOptions",
"-XX:SharedArchiveFile=./SharedStringsDedup.jsa",
"-XX:+UseCompressedOops", "-XX:+UseG1GC",
"-XX:+PrintSharedSpaces",
"-Xshare:dump");
new OutputAnalyzer(pb.start())
.shouldContain("Loading classes to share")
.shouldContain("Shared string table stats")
.shouldHaveExitValue(0);
// Run with -Xshare:auto
pb = ProcessTools.createJavaProcessBuilder(
"-XX:+UnlockDiagnosticVMOptions",
"-XX:SharedArchiveFile=./SharedStringsDedup.jsa",
"-XX:+UseCompressedOops", "-XX:+UseG1GC",
"-XX:+UseStringDeduplication",
"-Xshare:auto",
"-version");
new OutputAnalyzer(pb.start())
.shouldMatch("(java|openjdk) version")
.shouldHaveExitValue(0);
}
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* A custom system ClassLoader to define the module "m2" to during iterations of
* differing test runs within the test ModuleStress.java
*/
public class CustomSystemClassLoader extends ClassLoader {
public CustomSystemClassLoader() {
super();
}
public CustomSystemClassLoader(ClassLoader parent) {
super(parent);
}
}

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.test.lib.Asserts.*;
import java.lang.reflect.Layer;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
//
// ClassLoader1 --> defines m1 --> packages p1
// ClassLoader2 --> defines m2 --> packages p2
// Java System Class Loader --> defines m3 --> packages p3
//
// m1 can read m2
// package p2 in m2 is exported to m1 and m3
//
// class p1.c1 defined in m1 tries to access p2.c2 defined in m2
// Access allowed since m1 can read m2 and package p2 is exported to m1.
//
public class ModuleNonBuiltinCLMain {
// Create a Layer over the boot layer.
// Define modules within this layer to test access between
// publically defined classes within packages of those modules.
public void createLayerOnBoot() throws Throwable {
// Define module: m1
// Can read: java.base, m2
// Packages: p1
// Packages exported: p1 is exported to unqualifiedly
ModuleDescriptor descriptor_m1 =
new ModuleDescriptor.Builder("m1")
.requires("java.base")
.requires("m2")
.exports("p1")
.build();
// Define module: m2
// Can read: java.base, m3
// Packages: p2
// Packages exported: package p2 is exported to m1 and m3
Set<String> targets = new HashSet<>();
targets.add("m1");
targets.add("m3");
ModuleDescriptor descriptor_m2 =
new ModuleDescriptor.Builder("m2")
.requires("java.base")
.requires("m3")
.exports("p2", targets)
.build();
// Define module: m3
// Can read: java.base
// Packages: p3
// Packages exported: none
ModuleDescriptor descriptor_m3 =
new ModuleDescriptor.Builder("m3")
.requires("java.base")
.build();
// Set up a ModuleFinder containing all modules for this layer.
ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3);
// Resolves "m1"
Configuration cf = Layer.boot()
.configuration()
.resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
// map each module to differing user defined class loaders for this test
Map<String, ClassLoader> map = new HashMap<>();
Loader1 cl1 = new Loader1();
Loader2 cl2 = new Loader2();
ClassLoader cl3 = ClassLoader.getSystemClassLoader();
map.put("m1", cl1);
map.put("m2", cl2);
map.put("m3", cl3);
// Create Layer that contains m1 & m2
Layer layer = Layer.boot().defineModules(cf, map::get);
assertTrue(layer.findLoader("m1") == cl1);
assertTrue(layer.findLoader("m2") == cl2);
assertTrue(layer.findLoader("m3") == cl3);
assertTrue(layer.findLoader("java.base") == null);
// now use the same loader to load class p1.c1
Class p1_c1_class = cl1.loadClass("p1.c1");
try {
p1_c1_class.newInstance();
} catch (IllegalAccessError e) {
throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1");
}
}
public static void main(String args[]) throws Throwable {
ModuleNonBuiltinCLMain test = new ModuleNonBuiltinCLMain();
test.createLayerOnBoot();
}
static class Loader1 extends ClassLoader { }
static class Loader2 extends ClassLoader { }
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.test.lib.Asserts.*;
import java.lang.reflect.Layer;
import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
//
// ClassLoader1 --> defines m1 --> packages p1
// ClassLoader1 --> defines m2 --> packages p2
//
// m1 can read m2
// package p2 in m2 is exported to m1
//
// class p1.c1 defined in m1 tries to access p2.c2 defined in m2
// Access allowed since m1 can read m2 and package p2 is exported to m1.
//
public class ModuleSameCLMain {
// Create a Layer over the boot layer.
// Define modules within this layer to test access between
// publically defined classes within packages of those modules.
public void createLayerOnBoot() throws Throwable {
// Define module: m1
// Can read: java.base, m2
// Packages: p1
// Packages exported: p1 is exported to unqualifiedly
ModuleDescriptor descriptor_m1 =
new ModuleDescriptor.Builder("m1")
.requires("java.base")
.requires("m2")
.exports("p1")
.build();
// Define module: m2
// Can read: java.base
// Packages: p2
// Packages exported: package p2 is exported to m1
ModuleDescriptor descriptor_m2 =
new ModuleDescriptor.Builder("m2")
.requires("java.base")
.exports("p2", "m1")
.build();
// Set up a ModuleFinder containing all modules for this layer.
ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2);
// Resolves "m1"
Configuration cf = Layer.boot()
.configuration()
.resolveRequires(finder, ModuleFinder.of(), Set.of("m1"));
// map each module to the same class loader for this test
Map<String, ClassLoader> map = new HashMap<>();
Loader1 cl1 = new Loader1();
map.put("m1", cl1);
map.put("m2", cl1);
// Create Layer that contains m1 & m2
Layer layer = Layer.boot().defineModules(cf, map::get);
assertTrue(layer.findLoader("m1") == cl1);
assertTrue(layer.findLoader("m2") == cl1);
assertTrue(layer.findLoader("java.base") == null);
// now use the same loader to load class p1.c1
Class p1_c1_class = cl1.loadClass("p1.c1");
try {
p1_c1_class.newInstance();
} catch (IllegalAccessError e) {
throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1");
}
}
public static void main(String args[]) throws Throwable {
ModuleSameCLMain test = new ModuleSameCLMain();
test.createLayerOnBoot();
}
static class Loader1 extends ClassLoader { }
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8159262
* @summary Test differing scenarios where a module's readability list and a package's exportability list should be walked
* @modules java.base/jdk.internal.misc
* @library /testlibrary /test/lib
* @compile ../AccessCheck/ModuleLibrary.java
* @compile ModuleSameCLMain.java
* @compile ModuleNonBuiltinCLMain.java
* @compile CustomSystemClassLoader.java
* @build ModuleStress
* @run main/othervm ModuleStress
*/
import jdk.test.lib.*;
import java.io.File;
public class ModuleStress {
public static void main(String[] args) throws Exception {
// Test #1: java -version
// All modules' readability lists and packages' exportability
// lists should contain only modules defined to the 3 builtin
// loaders (boot, application, platform). Thus there is
// not a need to walk those lists at a GC safepoint since
// those loaders never die.
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"-version");
OutputAnalyzer oa = new OutputAnalyzer(pb.start());
oa.shouldNotContain("must be walked")
.shouldNotContain("being walked")
.shouldHaveExitValue(0);
// Next 2 tests involve the use of class p1.c1 and p2.c2
String source1 = "package p1;" +
"import p2.c2;" +
"public class c1 {" +
" public c1() {" +
" p2.c2 c2_obj = new p2.c2();" +
" c2_obj.method2();" +
" }" +
"}";
String source2 = "package p2;" +
"public class c2 {" +
" public void method2() { }" +
"}";
ClassFileInstaller.writeClassToDisk("p2/c2",
InMemoryJavaCompiler.compile("p2.c2", source2), System.getProperty("test.classes"));
ClassFileInstaller.writeClassToDisk("p1/c1",
InMemoryJavaCompiler.compile("p1.c1", source1), System.getProperty("test.classes"));
// Test #2: Load two modules defined to the same customer class loader.
// m1's module readability list and package p2's exportability should
// not be walked at a GC safepoint since both modules are defined to
// the same loader and thus have the exact same life cycle.
pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"ModuleSameCLMain");
oa = new OutputAnalyzer(pb.start());
oa.shouldNotContain("must be walked")
.shouldNotContain("being walked")
.shouldHaveExitValue(0);
// Test #3: Load two modules in differing custom class loaders.
// m1's module readability list and package p2's exportability list must
// be walked at a GC safepoint since both modules are defined to non-builtin
// class loaders which could die and thus be unloaded.
pb = ProcessTools.createJavaProcessBuilder(
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"ModuleNonBuiltinCLMain");
oa = new OutputAnalyzer(pb.start());
oa.shouldContain("module m1 reads list must be walked")
.shouldContain("package p2 defined in module m2, exports list must be walked")
.shouldNotContain("module m2 reads list must be walked")
.shouldHaveExitValue(0);
// Test #4: Load two modules in differing custom class loaders,
// of which one has been designated as the custom system class loader
// via -Djava.system.class.loader=CustomSystemClassLoader. Since
// m3 is defined to the system class loader, m2's module readability
// list does not have to be walked at a GC safepoint, but package p2's
// exportability list does.
pb = ProcessTools.createJavaProcessBuilder(
"-Djava.system.class.loader=CustomSystemClassLoader",
"-Xbootclasspath/a:.",
"-Xlog:modules=trace",
"ModuleNonBuiltinCLMain");
oa = new OutputAnalyzer(pb.start());
oa.shouldContain("package p2 defined in module m2, exports list must be walked")
.shouldNotContain("module m2 reads list must be walked")
.shouldHaveExitValue(0);
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8159262
* @summary layers over the boot layer are repeatedly created, during this iteration, GCs are forced to verify correct walk of module and package lists.
* @modules java.base/jdk.internal.misc
* @library /testlibrary /test/lib
* @compile ../CompilerUtils.java
* @build ModuleStressGC
* @run main/othervm ModuleStressGC
*/
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.*;
public class ModuleStressGC {
private static final String TEST_SRC = System.getProperty("test.src");
private static final String TEST_CLASSES = System.getProperty("test.classes");
private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods");
/**
* Compile two module definitions used by the test, jdk.test and jdk.translet.
*/
public static void main(String[] args) throws Exception {
boolean compiled;
// Compile module jdk.test declaration
compiled = CompilerUtils.compile(
SRC_DIR.resolve("jdk.test"),
MODS_DIR.resolve("jdk.test"));
if (!compiled) {
throw new RuntimeException("Test failed to compile module jdk.test");
}
// Compile module jdk.translet declaration
compiled = CompilerUtils.compile(
SRC_DIR.resolve("jdk.translet"),
MODS_DIR.resolve("jdk.translet"),
"-XaddExports:jdk.test/test=jdk.translet",
"-mp", MODS_DIR.toString());
if (!compiled) {
throw new RuntimeException("Test failed to compile module jdk.translet");
}
// Sanity check that the test, jdk.test/test/MainGC.java,
// correctly walks module jdk.test's reads list and package
// test's, defined to module jdk.translet, export list at
// GC safepoints.
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-Xlog:modules=trace",
"-mp", MODS_DIR.toString(),
"-m", "jdk.test/test.MainGC");
OutputAnalyzer oa = new OutputAnalyzer(pb.start());
oa.shouldContain("package test defined in module jdk.test, exports list being walked")
.shouldContain("module jdk.test reads list being walked")
.shouldHaveExitValue(0);
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package test;
import java.lang.module.Configuration;
import java.lang.module.ModuleFinder;
import java.lang.reflect.Layer;
import java.lang.reflect.Method;
import java.lang.reflect.Module;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MainGC {
private static final Path MODS_DIR = Paths.get(System.getProperty("jdk.module.path"));
static final String MODULE_NAME = "jdk.translet";
public static void main(String[] args) throws Exception {
ModuleFinder finder = ModuleFinder.of(MODS_DIR);
Layer layerBoot = Layer.boot();
Configuration cf = layerBoot
.configuration()
.resolveRequires(ModuleFinder.of(), finder, Set.of(MODULE_NAME));
Module testModule = MainGC.class.getModule();
ClassLoader scl = ClassLoader.getSystemClassLoader();
// Create an unique module/class loader in a layer above the boot layer.
// Export this module to the jdk.test/test package.
// Add a read edge from module jdk.test to this module.
Callable<Void> task = new Callable<Void>() {
@Override
public Void call() throws Exception {
Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl);
Module transletModule = layer.findModule(MODULE_NAME).get();
testModule.addExports("test", transletModule);
testModule.addReads(transletModule);
Class<?> c = layer.findLoader(MODULE_NAME).loadClass("translet.MainGC");
Method method = c.getDeclaredMethod("go");
method.invoke(null);
return null;
}
};
List<Future<Void>> results = new ArrayList<>();
// Repeatedly create the layer above stressing the exportation of
// package jdk.test/test to several different modules.
ExecutorService pool = Executors.newFixedThreadPool(Math.min(100, Runtime.getRuntime().availableProcessors()*10));
try {
for (int i = 0; i < 10000; i++) {
results.add(pool.submit(task));
// At specified intervals, force a GC. This provides an
// opportunity to verify that both the module jdk.test's reads
// and the package test's, which is defined to jdk.test, exports
// lists are being walked.
if (i == 3000 || i == 6000 || i == 9000) {
System.gc();
}
}
} finally {
pool.shutdown();
}
int passed = 0;
int failed = 0;
// The failed state should be 0, the created modules in layers above the
// boot layer should be allowed access to the contents of the jdk.test/test
// package since that package was exported to the transletModule above.
for (Future<Void> result : results) {
try {
result.get();
passed++;
} catch (Throwable x) {
x.printStackTrace();
failed++;
}
}
System.out.println("passed: " + passed);
System.out.println("failed: " + failed);
}
public static void callback() { }
}

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package translet;
public class MainGC {
public static void go() {
test.MainGC.callback();
}
}

View File

@ -369,3 +369,4 @@ f8899b1884e2c4a000dbcc5b1a80954245fe462e jdk-9+122
e04a15153cc293f05fcd60bc98236f50e16af46a jdk-9+124
493eb91ec32a6dea7604cfbd86c10045ad9af15b jdk-9+125
15722f71281f034bc696d8b96136da2ef34da44f jdk-9+126
bdc3c0b737efbf899709eb3121ce760dcfb51151 jdk-9+127

View File

@ -372,3 +372,4 @@ c42decd28bbfa817347112ed6053b5fbd30517a2 jdk-9+123
1600da1665cd2cc127014e8c002b328ec33a9147 jdk-9+124
5b0570e3db29f6b8c80a4beac70d51284507b203 jdk-9+125
264a44128cd6286e598d5a849ceeb613c06269d0 jdk-9+126
06d706c70634775418dc79a2671780ba1c624fd2 jdk-9+127

View File

@ -169,7 +169,7 @@ class NTLM {
byte[] readSecurityBuffer(int offset) throws NTLMException {
int pos = readInt(offset+4);
if (pos == 0) return null;
if (pos == 0) return new byte[0];
try {
return Arrays.copyOfRange(
internal, pos, pos + readShort(offset));

View File

@ -1613,6 +1613,8 @@ public final class Math {
* @return (<i>a</i>&nbsp;&times;&nbsp;<i>b</i>&nbsp;+&nbsp;<i>c</i>)
* computed, as if with unlimited range and precision, and rounded
* once to the nearest {@code double} value
*
* @since 9
*/
// @HotSpotIntrinsicCandidate
public static double fma(double a, double b, double c) {
@ -1728,6 +1730,8 @@ public final class Math {
* @return (<i>a</i>&nbsp;&times;&nbsp;<i>b</i>&nbsp;+&nbsp;<i>c</i>)
* computed, as if with unlimited range and precision, and rounded
* once to the nearest {@code float} value
*
* @since 9
*/
// @HotSpotIntrinsicCandidate
public static float fma(float a, float b, float c) {

View File

@ -1276,6 +1276,8 @@ public final class StrictMath {
* @return (<i>a</i>&nbsp;&times;&nbsp;<i>b</i>&nbsp;+&nbsp;<i>c</i>)
* computed, as if with unlimited range and precision, and rounded
* once to the nearest {@code double} value
*
* @since 9
*/
public static double fma(double a, double b, double c) {
return Math.fma(a, b, c);
@ -1328,6 +1330,8 @@ public final class StrictMath {
* @return (<i>a</i>&nbsp;&times;&nbsp;<i>b</i>&nbsp;+&nbsp;<i>c</i>)
* computed, as if with unlimited range and precision, and rounded
* once to the nearest {@code float} value
*
* @since 9
*/
public static float fma(float a, float b, float c) {
return Math.fma(a, b, c);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it

View File

@ -3290,8 +3290,8 @@ public final class Files {
* a size of {@code 0}. All bytes in the byte array are written to the file.
* The method ensures that the file is closed when all bytes have been
* written (or an I/O error or other runtime exception is thrown). If an I/O
* error occurs then it may do so after the file has created or truncated,
* or after some bytes have been written to the file.
* error occurs then it may do so after the file has been created or
* truncated, or after some bytes have been written to the file.
*
* <p> <b>Usage example</b>: By default the method creates a new file or
* overwrites an existing file. Suppose you instead want to append bytes
@ -3360,7 +3360,8 @@ public final class Files {
* a size of {@code 0}. The method ensures that the file is closed when all
* lines have been written (or an I/O error or other runtime exception is
* thrown). If an I/O error occurs then it may do so after the file has
* created or truncated, or after some bytes have been written to the file.
* been created or truncated, or after some bytes have been written to the
* file.
*
* @param path
* the path to the file

View File

@ -124,7 +124,6 @@ package java.util;
* always well-defined for queues with the same elements but different
* ordering properties.
*
*
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.

View File

@ -68,6 +68,7 @@ import java.util.function.ToIntFunction;
import java.util.function.ToLongBiFunction;
import java.util.function.ToLongFunction;
import java.util.stream.Stream;
import jdk.internal.misc.Unsafe;
/**
* A hash table supporting full concurrency of retrievals and
@ -747,7 +748,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
/* ---------------- Table element access -------------- */
/*
* Volatile access methods are used for table elements as well as
* Atomic access methods are used for table elements as well as
* elements of in-progress next table while resizing. All uses of
* the tab arguments must be null checked by callers. All callers
* also paranoically precheck that tab's length is not zero (or an
@ -757,14 +758,12 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
* errors by users, these checks must operate on local variables,
* which accounts for some odd-looking inline assignments below.
* Note that calls to setTabAt always occur within locked regions,
* and so in principle require only release ordering, not
* full volatile semantics, but are currently coded as volatile
* writes to be conservative.
* and so require only release ordering.
*/
@SuppressWarnings("unchecked")
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
return (Node<K,V>)U.getObjectAcquire(tab, ((long)i << ASHIFT) + ABASE);
}
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
@ -773,7 +772,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
}
static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
U.putObjectRelease(tab, ((long)i << ASHIFT) + ABASE, v);
}
/* ---------------- Fields -------------- */
@ -3298,7 +3297,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
return true;
}
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private static final long LOCKSTATE;
static {
try {
@ -6341,7 +6340,7 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private static final long SIZECTL;
private static final long TRANSFERINDEX;
private static final long BASECOUNT;

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.Collection;
@ -292,64 +294,23 @@ public class ConcurrentLinkedDeque<E>
volatile Node<E> prev;
volatile E item;
volatile Node<E> next;
}
Node() { // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
}
/**
* Constructs a new node. Uses relaxed write because item can
* only be seen after publication via casNext or casPrev.
*/
Node(E item) {
U.putObject(this, ITEM, item);
}
boolean casItem(E cmp, E val) {
return U.compareAndSwapObject(this, ITEM, cmp, val);
}
void lazySetNext(Node<E> val) {
U.putObjectRelease(this, NEXT, val);
}
boolean casNext(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, NEXT, cmp, val);
}
void lazySetPrev(Node<E> val) {
U.putObjectRelease(this, PREV, val);
}
boolean casPrev(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, PREV, cmp, val);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long PREV;
private static final long ITEM;
private static final long NEXT;
static {
try {
PREV = U.objectFieldOffset
(Node.class.getDeclaredField("prev"));
ITEM = U.objectFieldOffset
(Node.class.getDeclaredField("item"));
NEXT = U.objectFieldOffset
(Node.class.getDeclaredField("next"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
/**
* Returns a new node holding item. Uses relaxed write because item
* can only be seen after piggy-backing publication via CAS.
*/
static <E> Node<E> newNode(E item) {
Node<E> node = new Node<E>();
ITEM.set(node, item);
return node;
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
final Node<E> newNode = newNode(Objects.requireNonNull(e));
restartFromHead:
for (;;)
@ -363,13 +324,13 @@ public class ConcurrentLinkedDeque<E>
continue restartFromHead;
else {
// p is first node
newNode.lazySetNext(p); // CAS piggyback
if (p.casPrev(null, newNode)) {
NEXT.set(newNode, p); // CAS piggyback
if (PREV.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
if (p != h) // hop two nodes at a time
casHead(h, newNode); // Failure is OK.
if (p != h) // hop two nodes at a time; failure is OK
HEAD.weakCompareAndSetVolatile(this, h, newNode);
return;
}
// Lost CAS race to another thread; re-read prev
@ -381,7 +342,7 @@ public class ConcurrentLinkedDeque<E>
* Links e as last element.
*/
private void linkLast(E e) {
final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
final Node<E> newNode = newNode(Objects.requireNonNull(e));
restartFromTail:
for (;;)
@ -395,13 +356,13 @@ public class ConcurrentLinkedDeque<E>
continue restartFromTail;
else {
// p is last node
newNode.lazySetPrev(p); // CAS piggyback
if (p.casNext(null, newNode)) {
PREV.set(newNode, p); // CAS piggyback
if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this deque,
// and for newNode to become "live".
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
if (p != t) // hop two nodes at a time; failure is OK
TAIL.weakCompareAndSetVolatile(this, t, newNode);
return;
}
// Lost CAS race to another thread; re-read next
@ -516,8 +477,8 @@ public class ConcurrentLinkedDeque<E>
updateTail(); // Ensure x is not reachable from tail
// Finally, actually gc-unlink
x.lazySetPrev(isFirst ? prevTerminator() : x);
x.lazySetNext(isLast ? nextTerminator() : x);
PREV.setRelease(x, isFirst ? prevTerminator() : x);
NEXT.setRelease(x, isLast ? nextTerminator() : x);
}
}
}
@ -531,7 +492,8 @@ public class ConcurrentLinkedDeque<E>
// assert first.item == null;
for (Node<E> o = null, p = next, q;;) {
if (p.item != null || (q = p.next) == null) {
if (o != null && p.prev != p && first.casNext(next, p)) {
if (o != null && p.prev != p &&
NEXT.compareAndSet(first, next, p)) {
skipDeletedPredecessors(p);
if (first.prev == null &&
(p.next == null || p.item != null) &&
@ -541,8 +503,8 @@ public class ConcurrentLinkedDeque<E>
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
o.lazySetNext(o);
o.lazySetPrev(prevTerminator());
NEXT.setRelease(o, o);
PREV.setRelease(o, prevTerminator());
}
}
return;
@ -565,7 +527,8 @@ public class ConcurrentLinkedDeque<E>
// assert last.item == null;
for (Node<E> o = null, p = prev, q;;) {
if (p.item != null || (q = p.prev) == null) {
if (o != null && p.next != p && last.casPrev(prev, p)) {
if (o != null && p.next != p &&
PREV.compareAndSet(last, prev, p)) {
skipDeletedSuccessors(p);
if (last.next == null &&
(p.prev == null || p.item != null) &&
@ -575,8 +538,8 @@ public class ConcurrentLinkedDeque<E>
updateTail(); // Ensure o is not reachable from tail
// Finally, actually gc-unlink
o.lazySetPrev(o);
o.lazySetNext(nextTerminator());
PREV.setRelease(o, o);
NEXT.setRelease(o, nextTerminator());
}
}
return;
@ -607,7 +570,7 @@ public class ConcurrentLinkedDeque<E>
(q = (p = q).prev) == null) {
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
if (casHead(h, p))
if (HEAD.compareAndSet(this, h, p))
return;
else
continue restartFromHead;
@ -637,7 +600,7 @@ public class ConcurrentLinkedDeque<E>
(q = (p = q).next) == null) {
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
if (casTail(t, p))
if (TAIL.compareAndSet(this, t, p))
return;
else
continue restartFromTail;
@ -675,7 +638,7 @@ public class ConcurrentLinkedDeque<E>
}
// found active CAS target
if (prev == p || x.casPrev(prev, p))
if (prev == p || PREV.compareAndSet(x, prev, p))
return;
} while (x.item != null || x.next == null);
@ -706,7 +669,7 @@ public class ConcurrentLinkedDeque<E>
}
// found active CAS target
if (next == p || x.casNext(next, p))
if (next == p || NEXT.compareAndSet(x, next, p))
return;
} while (x.item != null || x.prev == null);
@ -751,7 +714,7 @@ public class ConcurrentLinkedDeque<E>
else if (p == h
// It is possible that p is PREV_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
|| casHead(h, p))
|| HEAD.compareAndSet(this, h, p))
return p;
else
continue restartFromHead;
@ -776,7 +739,7 @@ public class ConcurrentLinkedDeque<E>
else if (p == t
// It is possible that p is NEXT_TERMINATOR,
// but if so, the CAS is guaranteed to fail.
|| casTail(t, p))
|| TAIL.compareAndSet(this, t, p))
return p;
else
continue restartFromTail;
@ -802,7 +765,7 @@ public class ConcurrentLinkedDeque<E>
* Constructs an empty deque.
*/
public ConcurrentLinkedDeque() {
head = tail = new Node<E>(null);
head = tail = new Node<E>();
}
/**
@ -818,12 +781,12 @@ public class ConcurrentLinkedDeque<E>
// Copy c into a private chain of Nodes
Node<E> h = null, t = null;
for (E e : c) {
Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
Node<E> newNode = newNode(Objects.requireNonNull(e));
if (h == null)
h = t = newNode;
else {
t.lazySetNext(newNode);
newNode.lazySetPrev(t);
NEXT.set(t, newNode);
PREV.set(newNode, t);
t = newNode;
}
}
@ -836,12 +799,12 @@ public class ConcurrentLinkedDeque<E>
private void initHeadTail(Node<E> h, Node<E> t) {
if (h == t) {
if (h == null)
h = t = new Node<E>(null);
h = t = new Node<E>();
else {
// Avoid edge case of a single Node with non-null item.
Node<E> newNode = new Node<E>(null);
t.lazySetNext(newNode);
newNode.lazySetPrev(t);
Node<E> newNode = new Node<E>();
NEXT.set(t, newNode);
PREV.set(newNode, t);
t = newNode;
}
}
@ -934,7 +897,7 @@ public class ConcurrentLinkedDeque<E>
public E pollFirst() {
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.item;
if (item != null && p.casItem(item, null)) {
if (item != null && ITEM.compareAndSet(p, item, null)) {
unlink(p);
return item;
}
@ -945,7 +908,7 @@ public class ConcurrentLinkedDeque<E>
public E pollLast() {
for (Node<E> p = last(); p != null; p = pred(p)) {
E item = p.item;
if (item != null && p.casItem(item, null)) {
if (item != null && ITEM.compareAndSet(p, item, null)) {
unlink(p);
return item;
}
@ -1031,7 +994,8 @@ public class ConcurrentLinkedDeque<E>
Objects.requireNonNull(o);
for (Node<E> p = first(); p != null; p = succ(p)) {
E item = p.item;
if (item != null && o.equals(item) && p.casItem(item, null)) {
if (item != null && o.equals(item) &&
ITEM.compareAndSet(p, item, null)) {
unlink(p);
return true;
}
@ -1055,7 +1019,8 @@ public class ConcurrentLinkedDeque<E>
Objects.requireNonNull(o);
for (Node<E> p = last(); p != null; p = pred(p)) {
E item = p.item;
if (item != null && o.equals(item) && p.casItem(item, null)) {
if (item != null && o.equals(item) &&
ITEM.compareAndSet(p, item, null)) {
unlink(p);
return true;
}
@ -1159,12 +1124,12 @@ public class ConcurrentLinkedDeque<E>
// Copy c into a private chain of Nodes
Node<E> beginningOfTheEnd = null, last = null;
for (E e : c) {
Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
Node<E> newNode = newNode(Objects.requireNonNull(e));
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
last.lazySetNext(newNode);
newNode.lazySetPrev(last);
NEXT.set(last, newNode);
PREV.set(newNode, last);
last = newNode;
}
}
@ -1184,16 +1149,16 @@ public class ConcurrentLinkedDeque<E>
continue restartFromTail;
else {
// p is last node
beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
if (p.casNext(null, beginningOfTheEnd)) {
PREV.set(beginningOfTheEnd, p); // CAS piggyback
if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this deque.
if (!casTail(t, last)) {
if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
casTail(t, last);
TAIL.weakCompareAndSetVolatile(this, t, last);
}
return true;
}
@ -1586,41 +1551,38 @@ public class ConcurrentLinkedDeque<E>
Node<E> h = null, t = null;
for (Object item; (item = s.readObject()) != null; ) {
@SuppressWarnings("unchecked")
Node<E> newNode = new Node<E>((E) item);
Node<E> newNode = newNode((E) item);
if (h == null)
h = t = newNode;
else {
t.lazySetNext(newNode);
newNode.lazySetPrev(t);
NEXT.set(t, newNode);
PREV.set(newNode, t);
t = newNode;
}
}
initHeadTail(h, t);
}
private boolean casHead(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, HEAD, cmp, val);
}
private boolean casTail(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, TAIL, cmp, val);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
private static final long TAIL;
// VarHandle mechanics
private static final VarHandle HEAD;
private static final VarHandle TAIL;
private static final VarHandle PREV;
private static final VarHandle NEXT;
private static final VarHandle ITEM;
static {
PREV_TERMINATOR = new Node<Object>();
PREV_TERMINATOR.next = PREV_TERMINATOR;
NEXT_TERMINATOR = new Node<Object>();
NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
try {
HEAD = U.objectFieldOffset
(ConcurrentLinkedDeque.class.getDeclaredField("head"));
TAIL = U.objectFieldOffset
(ConcurrentLinkedDeque.class.getDeclaredField("tail"));
MethodHandles.Lookup l = MethodHandles.lookup();
HEAD = l.findVarHandle(ConcurrentLinkedDeque.class, "head",
Node.class);
TAIL = l.findVarHandle(ConcurrentLinkedDeque.class, "tail",
Node.class);
PREV = l.findVarHandle(Node.class, "prev", Node.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
ITEM = l.findVarHandle(Node.class, "item", Object.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@ -166,9 +168,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
* this is merely an optimization.
*
* When constructing a Node (before enqueuing it) we avoid paying
* for a volatile write to item by using Unsafe.putObject instead
* of a normal write. This allows the cost of enqueue to be
* "one-and-a-half" CASes.
* for a volatile write to item. This allows the cost of enqueue
* to be "one-and-a-half" CASes.
*
* Both head and tail may or may not point to a Node with a
* non-null item. If the queue is empty, all items must of course
@ -178,33 +179,21 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
* optimization.
*/
private static class Node<E> {
static final class Node<E> {
volatile E item;
volatile Node<E> next;
}
/**
* Returns a new node holding item. Uses relaxed write because item
* can only be seen after piggy-backing publication via casNext.
* can only be seen after piggy-backing publication via CAS.
*/
static <E> Node<E> newNode(E item) {
Node<E> node = new Node<E>();
U.putObject(node, ITEM, item);
ITEM.set(node, item);
return node;
}
static <E> boolean casItem(Node<E> node, E cmp, E val) {
return U.compareAndSwapObject(node, ITEM, cmp, val);
}
static <E> void lazySetNext(Node<E> node, Node<E> val) {
U.putObjectRelease(node, NEXT, val);
}
static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(node, NEXT, cmp, val);
}
/**
* A node from which the first live (non-deleted) node (if any)
* can be reached in O(1) time.
@ -256,7 +245,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
if (h == null)
h = t = newNode;
else {
lazySetNext(t, newNode);
NEXT.set(t, newNode);
t = newNode;
}
}
@ -286,8 +275,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
*/
final void updateHead(Node<E> h, Node<E> p) {
// assert h != null && p != null && (h == p || h.item == null);
if (h != p && casHead(h, p))
lazySetNext(h, h);
if (h != p && HEAD.compareAndSet(this, h, p))
NEXT.setRelease(h, h);
}
/**
@ -314,12 +303,12 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
Node<E> q = p.next;
if (q == null) {
// p is last node
if (casNext(p, null, newNode)) {
if (NEXT.compareAndSet(p, null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
if (p != t) // hop two nodes at a time; failure is OK
TAIL.weakCompareAndSetVolatile(this, t, newNode);
return true;
}
// Lost CAS race to another thread; re-read next
@ -342,7 +331,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
for (Node<E> h = head, p = h, q;;) {
E item = p.item;
if (item != null && casItem(p, item, null)) {
if (item != null && ITEM.compareAndSet(p, item, null)) {
// Successful CAS is the linearization point
// for item to be removed from this queue.
if (p != h) // hop two nodes at a time
@ -483,12 +472,12 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
next = succ(p);
continue;
}
removed = casItem(p, item, null);
removed = ITEM.compareAndSet(p, item, null);
}
next = succ(p);
if (pred != null && next != null) // unlink
casNext(pred, p, next);
NEXT.weakCompareAndSetVolatile(pred, p, next);
if (removed)
return true;
}
@ -520,7 +509,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
if (beginningOfTheEnd == null)
beginningOfTheEnd = last = newNode;
else {
lazySetNext(last, newNode);
NEXT.set(last, newNode);
last = newNode;
}
}
@ -532,15 +521,15 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
Node<E> q = p.next;
if (q == null) {
// p is last node
if (casNext(p, null, beginningOfTheEnd)) {
if (NEXT.compareAndSet(p, null, beginningOfTheEnd)) {
// Successful CAS is the linearization point
// for all elements to be added to this queue.
if (!casTail(t, last)) {
if (!TAIL.weakCompareAndSetVolatile(this, t, last)) {
// Try a little harder to update tail,
// since we may be adding many elements.
t = tail;
if (last.next == null)
casTail(t, last);
TAIL.weakCompareAndSetVolatile(this, t, last);
}
return true;
}
@ -744,7 +733,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
}
// unlink deleted nodes
if ((q = succ(p)) != null)
casNext(pred, p, q);
NEXT.compareAndSet(pred, p, q);
}
}
@ -801,7 +790,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
if (h == null)
h = t = newNode;
else {
lazySetNext(t, newNode);
NEXT.set(t, newNode);
t = newNode;
}
}
@ -919,31 +908,20 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
return new CLQSpliterator<E>(this);
}
private boolean casTail(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, TAIL, cmp, val);
}
private boolean casHead(Node<E> cmp, Node<E> val) {
return U.compareAndSwapObject(this, HEAD, cmp, val);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
private static final long TAIL;
private static final long ITEM;
private static final long NEXT;
// VarHandle mechanics
private static final VarHandle HEAD;
private static final VarHandle TAIL;
private static final VarHandle ITEM;
private static final VarHandle NEXT;
static {
try {
HEAD = U.objectFieldOffset
(ConcurrentLinkedQueue.class.getDeclaredField("head"));
TAIL = U.objectFieldOffset
(ConcurrentLinkedQueue.class.getDeclaredField("tail"));
ITEM = U.objectFieldOffset
(Node.class.getDeclaredField("item"));
NEXT = U.objectFieldOffset
(Node.class.getDeclaredField("next"));
MethodHandles.Lookup l = MethodHandles.lookup();
HEAD = l.findVarHandle(ConcurrentLinkedQueue.class, "head",
Node.class);
TAIL = l.findVarHandle(ConcurrentLinkedQueue.class, "tail",
Node.class);
ITEM = l.findVarHandle(Node.class, "item", Object.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
@ -401,7 +403,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* compareAndSet head node.
*/
private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
return U.compareAndSwapObject(this, HEAD, cmp, val);
return HEAD.compareAndSet(this, cmp, val);
}
/* ---------------- Nodes -------------- */
@ -444,14 +446,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* compareAndSet value field.
*/
boolean casValue(Object cmp, Object val) {
return U.compareAndSwapObject(this, VALUE, cmp, val);
return VALUE.compareAndSet(this, cmp, val);
}
/**
* compareAndSet next field.
*/
boolean casNext(Node<K,V> cmp, Node<K,V> val) {
return U.compareAndSwapObject(this, NEXT, cmp, val);
return NEXT.compareAndSet(this, cmp, val);
}
/**
@ -532,20 +534,16 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE;
private static final long NEXT;
// VarHandle mechanics
private static final VarHandle VALUE;
private static final VarHandle NEXT;
static {
try {
VALUE = U.objectFieldOffset
(Node.class.getDeclaredField("value"));
NEXT = U.objectFieldOffset
(Node.class.getDeclaredField("next"));
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(Node.class, "value", Object.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
throw new Error(e);
}
}
}
@ -577,7 +575,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* compareAndSet right field.
*/
final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
return U.compareAndSwapObject(this, RIGHT, cmp, val);
return RIGHT.compareAndSet(this, cmp, val);
}
/**
@ -613,13 +611,12 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return node.value != null && casRight(succ, succ.right);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long RIGHT;
// VarHandle mechanics
private static final VarHandle RIGHT;
static {
try {
RIGHT = U.objectFieldOffset
(Index.class.getDeclaredField("right"));
MethodHandles.Lookup l = MethodHandles.lookup();
RIGHT = l.findVarHandle(Index.class, "right", Index.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -3607,13 +3604,13 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
// VarHandle mechanics
private static final VarHandle HEAD;
static {
try {
HEAD = U.objectFieldOffset
(ConcurrentSkipListMap.class.getDeclaredField("head"));
MethodHandles.Lookup l = MethodHandles.lookup();
HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
HeadIndex.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
@ -507,15 +509,16 @@ public class ConcurrentSkipListSet<E>
// Support for resetting map in clone
private void setMap(ConcurrentNavigableMap<E,Object> map) {
U.putObjectVolatile(this, MAP, map);
MAP.setVolatile(this, map);
}
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long MAP;
// VarHandle mechanics
private static final VarHandle MAP;
static {
try {
MAP = U.objectFieldOffset
(ConcurrentSkipListSet.class.getDeclaredField("m"));
MethodHandles.Lookup l = MethodHandles.lookup();
MAP = l.findVarHandle(ConcurrentSkipListSet.class, "m",
ConcurrentNavigableMap.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -34,6 +34,7 @@
package java.util.concurrent;
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
@ -1541,17 +1542,21 @@ public class CopyOnWriteArrayList<E>
}
}
// Support for resetting lock while deserializing
/** Initializes the lock; for use when deserializing or cloning. */
private void resetLock() {
U.putObjectVolatile(this, LOCK, new Object());
}
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long LOCK;
static {
Field lockField = java.security.AccessController.doPrivileged(
(java.security.PrivilegedAction<Field>) () -> {
try {
Field f = CopyOnWriteArrayList.class
.getDeclaredField("lock");
f.setAccessible(true);
return f;
} catch (ReflectiveOperationException e) {
throw new Error(e);
}});
try {
LOCK = U.objectFieldOffset
(CopyOnWriteArrayList.class.getDeclaredField("lock"));
} catch (ReflectiveOperationException e) {
lockField.set(this, new Object());
} catch (IllegalAccessException e) {
throw new Error(e);
}
}

View File

@ -35,6 +35,9 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* A {@link ForkJoinTask} with a completion action performed when
* triggered and there are no remaining pending actions.
@ -524,7 +527,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
* @param delta the value to add
*/
public final void addToPendingCount(int delta) {
U.getAndAddInt(this, PENDING, delta);
PENDING.getAndAdd(this, delta);
}
/**
@ -536,7 +539,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
* @return {@code true} if successful
*/
public final boolean compareAndSetPendingCount(int expected, int count) {
return U.compareAndSwapInt(this, PENDING, expected, count);
return PENDING.compareAndSet(this, expected, count);
}
/**
@ -548,7 +551,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
public final int decrementPendingCountUnlessZero() {
int c;
do {} while ((c = pending) != 0 &&
!U.compareAndSwapInt(this, PENDING, c, c - 1));
!PENDING.weakCompareAndSetVolatile(this, c, c - 1));
return c;
}
@ -581,7 +584,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
return;
}
}
else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@ -604,7 +607,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
return;
}
}
else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
else if (PENDING.weakCompareAndSetVolatile(a, c, c - 1))
return;
}
}
@ -649,7 +652,7 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
for (int c;;) {
if ((c = pending) == 0)
return this;
else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
else if (PENDING.weakCompareAndSetVolatile(this, c, c - 1))
return null;
}
}
@ -753,13 +756,13 @@ public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
*/
protected void setRawResult(T t) { }
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long PENDING;
// VarHandle mechanics
private static final VarHandle PENDING;
static {
try {
PENDING = U.objectFieldOffset
(CountedCompleter.class.getDeclaredField("pending"));
MethodHandles.Lookup l = MethodHandles.lookup();
PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -36,6 +36,10 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
/**
* A synchronization point at which threads can pair and swap elements
* within pairs. Each thread presents some object on entry to the
@ -155,9 +159,7 @@ public class Exchanger<V> {
* a value that is enough for common platforms. Additionally,
* extra care elsewhere is taken to avoid other false/unintended
* sharing and to enhance locality, including adding padding (via
* @Contended) to Nodes, embedding "bound" as an Exchanger field,
* and reworking some park/unpark mechanics compared to
* LockSupport versions.
* @Contended) to Nodes, embedding "bound" as an Exchanger field.
*
* The arena starts out with only one used slot. We expand the
* effective arena size by tracking collisions; i.e., failed CASes
@ -234,12 +236,12 @@ public class Exchanger<V> {
* because most of the logic relies on reads of fields that are
* maintained as local variables so can't be nicely factored --
* mainly, here, bulky spin->yield->block/cancel code), and
* heavily dependent on intrinsics (Unsafe) to use inlined
* heavily dependent on intrinsics (VarHandles) to use inlined
* embedded CAS and related memory access operations (that tend
* not to be as readily inlined by dynamic compilers when they are
* hidden behind other methods that would more nicely name and
* encapsulate the intended effects). This includes the use of
* putXRelease to clear fields of the per-thread Nodes between
* setRelease to clear fields of the per-thread Nodes between
* uses. Note that field Node.item is not declared as volatile
* even though it is read by releasing threads, because they only
* do so after CAS operations that must precede access, and all
@ -252,10 +254,10 @@ public class Exchanger<V> {
*/
/**
* The byte distance (as a shift value) between any two used slots
* in the arena. 1 << ASHIFT should be at least cacheline size.
* The index distance (as a shift value) between any two used slots
* in the arena, spacing them out to avoid false sharing.
*/
private static final int ASHIFT = 7;
private static final int ASHIFT = 5;
/**
* The maximum supported arena index. The maximum allocatable
@ -356,27 +358,31 @@ public class Exchanger<V> {
*/
private final Object arenaExchange(Object item, boolean timed, long ns) {
Node[] a = arena;
int alen = a.length;
Node p = participant.get();
for (int i = p.index;;) { // access slot at i
int b, m, c; long j; // j is raw array offset
Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
if (q != null && U.compareAndSwapObject(a, j, q, null)) {
int b, m, c;
int j = (i << ASHIFT) + ((1 << ASHIFT) - 1);
if (j < 0 || j >= alen)
j = alen - 1;
Node q = (Node)AA.getAcquire(a, j);
if (q != null && AA.compareAndSet(a, j, q, null)) {
Object v = q.item; // release
q.match = item;
Thread w = q.parked;
if (w != null)
U.unpark(w);
LockSupport.unpark(w);
return v;
}
else if (i <= (m = (b = bound) & MMASK) && q == null) {
p.item = item; // offer
if (U.compareAndSwapObject(a, j, null, p)) {
if (AA.compareAndSet(a, j, null, p)) {
long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
Thread t = Thread.currentThread(); // wait
for (int h = p.hash, spins = SPINS;;) {
Object v = p.match;
if (v != null) {
U.putObjectRelease(p, MATCH, null);
MATCH.setRelease(p, null);
p.item = null; // clear for next use
p.hash = h;
return v;
@ -389,22 +395,24 @@ public class Exchanger<V> {
(--spins & ((SPINS >>> 1) - 1)) == 0)
Thread.yield(); // two yields per wait
}
else if (U.getObjectVolatile(a, j) != p)
else if (AA.getAcquire(a, j) != p)
spins = SPINS; // releaser hasn't set match yet
else if (!t.isInterrupted() && m == 0 &&
(!timed ||
(ns = end - System.nanoTime()) > 0L)) {
U.putObject(t, BLOCKER, this); // emulate LockSupport
p.parked = t; // minimize window
if (U.getObjectVolatile(a, j) == p)
U.park(false, ns);
if (AA.getAcquire(a, j) == p) {
if (ns == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, ns);
}
p.parked = null;
U.putObject(t, BLOCKER, null);
}
else if (U.getObjectVolatile(a, j) == p &&
U.compareAndSwapObject(a, j, p, null)) {
else if (AA.getAcquire(a, j) == p &&
AA.compareAndSet(a, j, p, null)) {
if (m != 0) // try to shrink
U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
BOUND.compareAndSet(this, b, b + SEQ - 1);
p.item = null;
p.hash = h;
i = p.index >>>= 1; // descend
@ -426,7 +434,7 @@ public class Exchanger<V> {
i = (i != m || m == 0) ? m : m - 1;
}
else if ((c = p.collides) < m || m == FULL ||
!U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
!BOUND.compareAndSet(this, b, b + SEQ + 1)) {
p.collides = c + 1;
i = (i == 0) ? m : i - 1; // cyclically traverse
}
@ -455,24 +463,24 @@ public class Exchanger<V> {
for (Node q;;) {
if ((q = slot) != null) {
if (U.compareAndSwapObject(this, SLOT, q, null)) {
if (SLOT.compareAndSet(this, q, null)) {
Object v = q.item;
q.match = item;
Thread w = q.parked;
if (w != null)
U.unpark(w);
LockSupport.unpark(w);
return v;
}
// create arena on contention, but continue until slot null
if (NCPU > 1 && bound == 0 &&
U.compareAndSwapInt(this, BOUND, 0, SEQ))
BOUND.compareAndSet(this, 0, SEQ))
arena = new Node[(FULL + 2) << ASHIFT];
}
else if (arena != null)
return null; // caller must reroute to arenaExchange
else {
p.item = item;
if (U.compareAndSwapObject(this, SLOT, null, p))
if (SLOT.compareAndSet(this, null, p))
break;
p.item = null;
}
@ -495,19 +503,21 @@ public class Exchanger<V> {
spins = SPINS;
else if (!t.isInterrupted() && arena == null &&
(!timed || (ns = end - System.nanoTime()) > 0L)) {
U.putObject(t, BLOCKER, this);
p.parked = t;
if (slot == p)
U.park(false, ns);
if (slot == p) {
if (ns == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, ns);
}
p.parked = null;
U.putObject(t, BLOCKER, null);
}
else if (U.compareAndSwapObject(this, SLOT, p, null)) {
else if (SLOT.compareAndSet(this, p, null)) {
v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
break;
}
}
U.putObjectRelease(p, MATCH, null);
MATCH.setRelease(p, null);
p.item = null;
p.hash = h;
return v;
@ -556,8 +566,9 @@ public class Exchanger<V> {
@SuppressWarnings("unchecked")
public V exchange(V x) throws InterruptedException {
Object v;
Node[] a;
Object item = (x == null) ? NULL_ITEM : x; // translate null args
if ((arena != null ||
if (((a = arena) != null ||
(v = slotExchange(item, false, 0L)) == null) &&
((Thread.interrupted() || // disambiguates null return
(v = arenaExchange(item, false, 0L)) == null)))
@ -623,31 +634,18 @@ public class Exchanger<V> {
return (v == NULL_ITEM) ? null : (V)v;
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long BOUND;
private static final long SLOT;
private static final long MATCH;
private static final long BLOCKER;
private static final int ABASE;
// VarHandle mechanics
private static final VarHandle BOUND;
private static final VarHandle SLOT;
private static final VarHandle MATCH;
private static final VarHandle AA;
static {
try {
BOUND = U.objectFieldOffset
(Exchanger.class.getDeclaredField("bound"));
SLOT = U.objectFieldOffset
(Exchanger.class.getDeclaredField("slot"));
MATCH = U.objectFieldOffset
(Node.class.getDeclaredField("match"));
BLOCKER = U.objectFieldOffset
(Thread.class.getDeclaredField("parkBlocker"));
int scale = U.arrayIndexScale(Node[].class);
if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
throw new Error("Unsupported array scale");
// ABASE absorbs padding in front of element 0
ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
MethodHandles.Lookup l = MethodHandles.lookup();
BOUND = l.findVarHandle(Exchanger.class, "bound", int.class);
SLOT = l.findVarHandle(Exchanger.class, "slot", Node.class);
MATCH = l.findVarHandle(Node.class, "match", Object.class);
AA = MethodHandles.arrayElementVarHandle(Node[].class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -36,6 +36,8 @@
package java.util.concurrent;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
@ -92,7 +94,7 @@ import java.util.concurrent.locks.ReentrantLock;
* encountering the exception; minimally only the latter.
*
* <p>It is possible to define and use ForkJoinTasks that may block,
* but doing do requires three further considerations: (1) Completion
* but doing so requires three further considerations: (1) Completion
* of few if any <em>other</em> tasks should be dependent on a task
* that blocks on external synchronization or I/O. Event-style async
* tasks that are never joined (for example, those subclassing {@link
@ -259,7 +261,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
for (int s;;) {
if ((s = status) < 0)
return s;
if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
if (STATUS.compareAndSet(this, s, s | completion)) {
if ((s >>> 16) != 0)
synchronized (this) { notifyAll(); }
return completion;
@ -297,7 +299,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
final void internalWait(long timeout) {
int s;
if ((s = status) >= 0 && // force completer to issue notify
U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
STATUS.compareAndSet(this, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
try { wait(timeout); } catch (InterruptedException ie) { }
@ -319,7 +321,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
if (s >= 0 && (s = status) >= 0) {
boolean interrupted = false;
do {
if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
if (STATUS.compareAndSet(this, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0) {
try {
@ -353,7 +355,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
0)) >= 0) {
while ((s = status) >= 0) {
if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
if (STATUS.compareAndSet(this, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
wait(0L);
@ -400,22 +402,24 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
// Exception table support
/**
* Table of exceptions thrown by tasks, to enable reporting by
* callers. Because exceptions are rare, we don't directly keep
* Hash table of exceptions thrown by tasks, to enable reporting
* by callers. Because exceptions are rare, we don't directly keep
* them with task objects, but instead use a weak ref table. Note
* that cancellation exceptions don't appear in the table, but are
* instead recorded as status values.
*
* Note: These statics are initialized below in static block.
* The exception table has a fixed capacity.
*/
private static final ExceptionNode[] exceptionTable;
private static final ReentrantLock exceptionTableLock;
private static final ReferenceQueue<Object> exceptionTableRefQueue;
private static final ExceptionNode[] exceptionTable
= new ExceptionNode[32];
/**
* Fixed capacity for exceptionTable.
*/
private static final int EXCEPTION_MAP_CAPACITY = 32;
/** Lock protecting access to exceptionTable. */
private static final ReentrantLock exceptionTableLock
= new ReentrantLock();
/** Reference queue of stale exceptionally completed tasks. */
private static final ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue
= new ReferenceQueue<ForkJoinTask<?>>();
/**
* Key-value nodes for exception table. The chained hash table
@ -435,7 +439,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
final long thrower; // use id not ref to avoid weak cycles
final int hashCode; // store task hashCode before weak ref disappears
ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
ReferenceQueue<Object> exceptionTableRefQueue) {
ReferenceQueue<ForkJoinTask<?>> exceptionTableRefQueue) {
super(task, exceptionTableRefQueue);
this.ex = ex;
this.next = next;
@ -599,9 +603,8 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
private static void expungeStaleExceptions() {
for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
if (x instanceof ExceptionNode) {
int hashCode = ((ExceptionNode)x).hashCode;
ExceptionNode[] t = exceptionTable;
int i = hashCode & (t.length - 1);
int i = ((ExceptionNode)x).hashCode & (t.length - 1);
ExceptionNode e = t[i];
ExceptionNode pred = null;
while (e != null) {
@ -1031,7 +1034,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
while ((s = status) >= 0 &&
(ns = deadline - System.nanoTime()) > 0L) {
if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
STATUS.compareAndSet(this, s, s | SIGNAL)) {
synchronized (this) {
if (status >= 0)
wait(ms); // OK to throw InterruptedException
@ -1324,8 +1327,8 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
*/
public final short setForkJoinTaskTag(short newValue) {
for (int s;;) {
if (U.compareAndSwapInt(this, STATUS, s = status,
(s & ~SMASK) | (newValue & SMASK)))
if (STATUS.compareAndSet(this, s = status,
(s & ~SMASK) | (newValue & SMASK)))
return (short)s;
}
}
@ -1348,8 +1351,8 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
for (int s;;) {
if ((short)(s = status) != expect)
return false;
if (U.compareAndSwapInt(this, STATUS, s,
(s & ~SMASK) | (update & SMASK)))
if (STATUS.compareAndSet(this, s,
(s & ~SMASK) | (update & SMASK)))
return true;
}
}
@ -1510,17 +1513,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
setExceptionalCompletion((Throwable)ex);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATUS;
// VarHandle mechanics
private static final VarHandle STATUS;
static {
exceptionTableLock = new ReentrantLock();
exceptionTableRefQueue = new ReferenceQueue<Object>();
exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
try {
STATUS = U.objectFieldOffset
(ForkJoinTask.class.getDeclaredField("status"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -66,8 +66,9 @@ public class ForkJoinWorkerThread extends Thread {
* owning thread.
*
* Support for (non-public) subclass InnocuousForkJoinWorkerThread
* requires that we break quite a lot of encapsulation (via Unsafe)
* both here and in the subclass to access and set Thread fields.
* requires that we break quite a lot of encapsulation (via helper
* methods in ThreadLocalRandom) both here and in the subclass to
* access and set Thread fields.
*/
final ForkJoinPool pool; // the pool this thread works in
@ -92,8 +93,8 @@ public class ForkJoinWorkerThread extends Thread {
ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
AccessControlContext acc) {
super(threadGroup, null, "aForkJoinWorkerThread");
U.putObjectRelease(this, INHERITEDACCESSCONTROLCONTEXT, acc);
eraseThreadLocals(); // clear before registering
ThreadLocalRandom.setInheritedAccessControlContext(this, acc);
ThreadLocalRandom.eraseThreadLocals(this); // clear before registering
this.pool = pool;
this.workQueue = pool.registerWorker(this);
}
@ -170,38 +171,12 @@ public class ForkJoinWorkerThread extends Thread {
}
}
/**
* Erases ThreadLocals by nulling out Thread maps.
*/
final void eraseThreadLocals() {
U.putObject(this, THREADLOCALS, null);
U.putObject(this, INHERITABLETHREADLOCALS, null);
}
/**
* Non-public hook method for InnocuousForkJoinWorkerThread.
*/
void afterTopLevelExec() {
}
// Set up to allow setting thread fields in constructor
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long THREADLOCALS;
private static final long INHERITABLETHREADLOCALS;
private static final long INHERITEDACCESSCONTROLCONTEXT;
static {
try {
THREADLOCALS = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocals"));
INHERITABLETHREADLOCALS = U.objectFieldOffset
(Thread.class.getDeclaredField("inheritableThreadLocals"));
INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
(Thread.class.getDeclaredField("inheritedAccessControlContext"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
/**
* A worker thread that has no permissions, is not a member of any
* user-defined ThreadGroup, and erases all ThreadLocals after
@ -210,7 +185,7 @@ public class ForkJoinWorkerThread extends Thread {
static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
/** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
private static final ThreadGroup innocuousThreadGroup =
createThreadGroup();
ThreadLocalRandom.createThreadGroup("InnocuousForkJoinWorkerThreadGroup");
/** An AccessControlContext supporting no privileges */
private static final AccessControlContext INNOCUOUS_ACC =
@ -225,7 +200,7 @@ public class ForkJoinWorkerThread extends Thread {
@Override // to erase ThreadLocals
void afterTopLevelExec() {
eraseThreadLocals();
ThreadLocalRandom.eraseThreadLocals(this);
}
@Override // to always report system loader
@ -241,33 +216,5 @@ public class ForkJoinWorkerThread extends Thread {
throw new SecurityException("setContextClassLoader");
}
/**
* Returns a new group with the system ThreadGroup (the
* topmost, parent-less group) as parent. Uses Unsafe to
* traverse Thread.group and ThreadGroup.parent fields.
*/
private static ThreadGroup createThreadGroup() {
try {
jdk.internal.misc.Unsafe u = jdk.internal.misc.Unsafe.getUnsafe();
long tg = u.objectFieldOffset
(Thread.class.getDeclaredField("group"));
long gp = u.objectFieldOffset
(ThreadGroup.class.getDeclaredField("parent"));
ThreadGroup group = (ThreadGroup)
u.getObject(Thread.currentThread(), tg);
while (group != null) {
ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
if (parent == null)
return new ThreadGroup(group,
"InnocuousForkJoinWorkerThreadGroup");
group = parent;
}
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
// fall through if null as cannot-happen safeguard
throw new Error("Cannot create ThreadGroup");
}
}
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.locks.LockSupport;
/**
@ -69,9 +71,6 @@ public class FutureTask<V> implements RunnableFuture<V> {
* cancellation races. Sync control in the current design relies
* on a "state" field updated via CAS to track completion, along
* with a simple Treiber stack to hold waiting threads.
*
* Style note: As usual, we bypass overhead of using
* AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
*/
/**
@ -163,9 +162,8 @@ public class FutureTask<V> implements RunnableFuture<V> {
}
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
U.compareAndSwapInt(this, STATE, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
if (!(state == NEW && STATE.compareAndSet
(this, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
@ -174,7 +172,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
if (t != null)
t.interrupt();
} finally { // final state
U.putIntRelease(this, STATE, INTERRUPTED);
STATE.setRelease(this, INTERRUPTED);
}
}
} finally {
@ -228,9 +226,9 @@ public class FutureTask<V> implements RunnableFuture<V> {
* @param v the value
*/
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = v;
U.putIntRelease(this, STATE, NORMAL); // final state
STATE.setRelease(this, NORMAL); // final state
finishCompletion();
}
}
@ -246,16 +244,16 @@ public class FutureTask<V> implements RunnableFuture<V> {
* @param t the cause of failure
*/
protected void setException(Throwable t) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
if (STATE.compareAndSet(this, NEW, COMPLETING)) {
outcome = t;
U.putIntRelease(this, STATE, EXCEPTIONAL); // final state
STATE.setRelease(this, EXCEPTIONAL); // final state
finishCompletion();
}
}
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
!RUNNER.compareAndSet(this, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
@ -296,7 +294,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
*/
protected boolean runAndReset() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
!RUNNER.compareAndSet(this, null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
@ -363,7 +361,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q, null)) {
if (WAITERS.weakCompareAndSetVolatile(this, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
@ -425,8 +423,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
q = new WaitNode();
}
else if (!queued)
queued = U.compareAndSwapObject(this, WAITERS,
q.next = waiters, q);
queued = WAITERS.weakCompareAndSetVolatile(this, q.next = waiters, q);
else if (timed) {
final long parkNanos;
if (startTime == 0L) { // first time
@ -475,7 +472,7 @@ public class FutureTask<V> implements RunnableFuture<V> {
if (pred.thread == null) // check for race
continue retry;
}
else if (!U.compareAndSwapObject(this, WAITERS, q, s))
else if (!WAITERS.compareAndSet(this, q, s))
continue retry;
}
break;
@ -483,19 +480,16 @@ public class FutureTask<V> implements RunnableFuture<V> {
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATE;
private static final long RUNNER;
private static final long WAITERS;
// VarHandle mechanics
private static final VarHandle STATE;
private static final VarHandle RUNNER;
private static final VarHandle WAITERS;
static {
try {
STATE = U.objectFieldOffset
(FutureTask.class.getDeclaredField("state"));
RUNNER = U.objectFieldOffset
(FutureTask.class.getDeclaredField("runner"));
WAITERS = U.objectFieldOffset
(FutureTask.class.getDeclaredField("waiters"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(FutureTask.class, "state", int.class);
RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@ -444,7 +446,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
/**
* Queue nodes. Uses Object, not E, for items to allow forgetting
* them after use. Relies heavily on Unsafe mechanics to minimize
* them after use. Relies heavily on VarHandles to minimize
* unnecessary ordering constraints: Writes that are intrinsically
* ordered wrt other accesses or CASes use simple relaxed forms.
*/
@ -456,12 +458,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
// CAS methods for fields
final boolean casNext(Node cmp, Node val) {
return U.compareAndSwapObject(this, NEXT, cmp, val);
return NEXT.compareAndSet(this, cmp, val);
}
final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class;
return U.compareAndSwapObject(this, ITEM, cmp, val);
return ITEM.compareAndSet(this, cmp, val);
}
/**
@ -469,7 +471,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* only be seen after publication via casNext.
*/
Node(Object item, boolean isData) {
U.putObject(this, ITEM, item); // relaxed write
ITEM.set(this, item); // relaxed write
this.isData = isData;
}
@ -478,7 +480,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* only after CASing head field, so uses relaxed write.
*/
final void forgetNext() {
U.putObject(this, NEXT, this);
NEXT.set(this, this);
}
/**
@ -491,8 +493,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* else we don't care).
*/
final void forgetContents() {
U.putObject(this, ITEM, this);
U.putObject(this, WAITER, null);
ITEM.set(this, this);
WAITER.set(this, null);
}
/**
@ -537,19 +539,16 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
private static final long serialVersionUID = -3375979862319811754L;
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long ITEM;
private static final long NEXT;
private static final long WAITER;
// VarHandle mechanics
private static final VarHandle ITEM;
private static final VarHandle NEXT;
private static final VarHandle WAITER;
static {
try {
ITEM = U.objectFieldOffset
(Node.class.getDeclaredField("item"));
NEXT = U.objectFieldOffset
(Node.class.getDeclaredField("next"));
WAITER = U.objectFieldOffset
(Node.class.getDeclaredField("waiter"));
MethodHandles.Lookup l = MethodHandles.lookup();
ITEM = l.findVarHandle(Node.class, "item", Object.class);
NEXT = l.findVarHandle(Node.class, "next", Node.class);
WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -567,15 +566,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
// CAS methods for fields
private boolean casTail(Node cmp, Node val) {
return U.compareAndSwapObject(this, TAIL, cmp, val);
return TAIL.compareAndSet(this, cmp, val);
}
private boolean casHead(Node cmp, Node val) {
return U.compareAndSwapObject(this, HEAD, cmp, val);
return HEAD.compareAndSet(this, cmp, val);
}
private boolean casSweepVotes(int cmp, int val) {
return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
return SWEEPVOTES.compareAndSet(this, cmp, val);
}
/*
@ -1562,20 +1561,19 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
private static final long TAIL;
private static final long SWEEPVOTES;
// VarHandle mechanics
private static final VarHandle HEAD;
private static final VarHandle TAIL;
private static final VarHandle SWEEPVOTES;
static {
try {
HEAD = U.objectFieldOffset
(LinkedTransferQueue.class.getDeclaredField("head"));
TAIL = U.objectFieldOffset
(LinkedTransferQueue.class.getDeclaredField("tail"));
SWEEPVOTES = U.objectFieldOffset
(LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
MethodHandles.Lookup l = MethodHandles.lookup();
HEAD = l.findVarHandle(LinkedTransferQueue.class, "head",
Node.class);
TAIL = l.findVarHandle(LinkedTransferQueue.class, "tail",
Node.class);
SWEEPVOTES = l.findVarHandle(LinkedTransferQueue.class, "sweepVotes",
int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;
@ -221,7 +223,6 @@ import java.util.concurrent.locks.LockSupport;
* phaser.arriveAndDeregister();
* }}</pre>
*
*
* <p>To create a set of {@code n} tasks using a tree of phasers, you
* could use code of the following form, assuming a Task class with a
* constructor accepting a {@code Phaser} that it registers with upon
@ -384,7 +385,7 @@ public class Phaser {
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
if (STATE.compareAndSet(this, s, s-=adjust)) {
if (unarrived == 1) {
long n = s & PARTIES_MASK; // base of next state
int nextUnarrived = (int)n >>> PARTIES_SHIFT;
@ -397,12 +398,12 @@ public class Phaser {
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
U.compareAndSwapLong(this, STATE, s, n);
STATE.compareAndSet(this, s, n);
releaseWaiters(phase);
}
else if (nextUnarrived == 0) { // propagate deregistration
phase = parent.doArrive(ONE_DEREGISTER);
U.compareAndSwapLong(this, STATE, s, s | EMPTY);
STATE.compareAndSet(this, s, s | EMPTY);
}
else
phase = parent.doArrive(ONE_ARRIVAL);
@ -437,13 +438,13 @@ public class Phaser {
if (parent == null || reconcileState() == s) {
if (unarrived == 0) // wait out advance
root.internalAwaitAdvance(phase, null);
else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
else if (STATE.compareAndSet(this, s, s + adjust))
break;
}
}
else if (parent == null) { // 1st root registration
long next = ((long)phase << PHASE_SHIFT) | adjust;
if (U.compareAndSwapLong(this, STATE, s, next))
if (STATE.compareAndSet(this, s, next))
break;
}
else {
@ -455,8 +456,8 @@ public class Phaser {
// finish registration whenever parent registration
// succeeded, even when racing with termination,
// since these are part of the same "transaction".
while (!U.compareAndSwapLong
(this, STATE, s,
while (!STATE.weakCompareAndSetVolatile
(this, s,
((long)phase << PHASE_SHIFT) | adjust)) {
s = state;
phase = (int)(root.state >>> PHASE_SHIFT);
@ -487,8 +488,8 @@ public class Phaser {
// CAS to root phase with current parties, tripping unarrived
while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
(int)(s >>> PHASE_SHIFT) &&
!U.compareAndSwapLong
(this, STATE, s,
!STATE.weakCompareAndSetVolatile
(this, s,
s = (((long)phase << PHASE_SHIFT) |
((phase < 0) ? (s & COUNTS_MASK) :
(((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
@ -677,7 +678,7 @@ public class Phaser {
int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
if (unarrived <= 0)
throw new IllegalStateException(badArrive(s));
if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
if (STATE.compareAndSet(this, s, s -= ONE_ARRIVAL)) {
if (unarrived > 1)
return root.internalAwaitAdvance(phase, null);
if (root != this)
@ -692,7 +693,7 @@ public class Phaser {
n |= nextUnarrived;
int nextPhase = (phase + 1) & MAX_PHASE;
n |= (long)nextPhase << PHASE_SHIFT;
if (!U.compareAndSwapLong(this, STATE, s, n))
if (!STATE.compareAndSet(this, s, n))
return (int)(state >>> PHASE_SHIFT); // terminated
releaseWaiters(phase);
return nextPhase;
@ -808,7 +809,7 @@ public class Phaser {
final Phaser root = this.root;
long s;
while ((s = root.state) >= 0) {
if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
if (STATE.compareAndSet(root, s, s | TERMINATION_BIT)) {
// signal all threads
releaseWaiters(0); // Waiters on evenQ
releaseWaiters(1); // Waiters on oddQ
@ -1043,6 +1044,8 @@ public class Phaser {
node = new QNode(this, phase, false, false, 0L);
node.wasInterrupted = interrupted;
}
else
Thread.onSpinWait();
}
else if (node.isReleasable()) // done or aborted
break;
@ -1131,14 +1134,12 @@ public class Phaser {
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATE;
// VarHandle mechanics
private static final VarHandle STATE;
static {
try {
STATE = U.objectFieldOffset
(Phaser.class.getDeclaredField("state"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(Phaser.class, "state", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Arrays;
import java.util.Collection;
@ -289,7 +291,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
@ -1009,13 +1011,14 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
return new PBQSpliterator<E>(this, null, 0, -1);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long ALLOCATIONSPINLOCK;
// VarHandle mechanics
private static final VarHandle ALLOCATIONSPINLOCK;
static {
try {
ALLOCATIONSPINLOCK = U.objectFieldOffset
(PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
MethodHandles.Lookup l = MethodHandles.lookup();
ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class,
"allocationSpinLock",
int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,6 +35,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;
@ -866,7 +868,7 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
/** Subscriber for method consume */
private static final class ConsumerSubscriber<T>
implements Flow.Subscriber<T> {
implements Flow.Subscriber<T> {
final CompletableFuture<Void> status;
final Consumer<? super T> consumer;
Flow.Subscription subscription;
@ -906,7 +908,7 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
*/
@SuppressWarnings("serial")
static final class ConsumerTask<T> extends ForkJoinTask<Void>
implements Runnable {
implements Runnable, CompletableFuture.AsynchronousCompletionTask {
final BufferedSubscription<T> consumer;
ConsumerTask(BufferedSubscription<T> consumer) {
this.consumer = consumer;
@ -959,11 +961,9 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
* Blocking control relies on the "waiter" field. Producers set
* the field before trying to block, but must then recheck (via
* offer) before parking. Signalling then just unparks and clears
* waiter field. If the producer and consumer are both in the same
* ForkJoinPool, or consumers are running in commonPool, the
* producer attempts to help run consumer tasks that it forked
* before blocking. To avoid potential cycles, only one level of
* helping is currently supported.
* waiter field. If the producer and/or consumer are using a
* ForkJoinPool, the producer attempts to help run consumer tasks
* via ForkJoinPool.helpAsyncBlocker before blocking.
*
* This class uses @Contended and heuristic field declaration
* ordering to reduce false-sharing-based memory contention among
@ -983,7 +983,6 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
volatile long demand; // # unfilled requests
int maxCapacity; // reduced on OOME
int putStat; // offer result for ManagedBlocker
int helpDepth; // nested helping depth (at most 1)
volatile int ctl; // atomic run state flags
volatile int head; // next position to take
int tail; // next position to put
@ -1077,7 +1076,7 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
alloc = true;
}
else {
U.fullFence(); // recheck
VarHandle.fullFence(); // recheck
int h = head, t = tail, size = t + 1 - h;
if (cap >= size) {
a[(cap - 1) & t] = item;
@ -1116,10 +1115,10 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
if (a != null && cap > 0) {
int mask = cap - 1;
for (int j = head; j != t; ++j) {
long k = ((long)(j & mask) << ASHIFT) + ABASE;
Object x = U.getObjectVolatile(a, k);
int k = j & mask;
Object x = QA.getAcquire(a, k);
if (x != null && // races with consumer
U.compareAndSwapObject(a, k, x, null))
QA.compareAndSet(a, k, x, null))
newArray[j & newMask] = x;
}
}
@ -1136,100 +1135,43 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
* initial offer return 0.
*/
final int submit(T item) {
int stat; Executor e; ForkJoinWorkerThread w;
if ((stat = offer(item)) == 0 && helpDepth == 0 &&
((e = executor) instanceof ForkJoinPool)) {
helpDepth = 1;
Thread thread = Thread.currentThread();
if ((thread instanceof ForkJoinWorkerThread) &&
((w = (ForkJoinWorkerThread)thread)).getPool() == e)
stat = internalHelpConsume(w.workQueue, item);
else if (e == ForkJoinPool.commonPool())
stat = externalHelpConsume
(ForkJoinPool.commonSubmitterQueue(), item);
helpDepth = 0;
}
if (stat == 0 && (stat = offer(item)) == 0) {
int stat;
if ((stat = offer(item)) == 0) {
putItem = item;
timeout = 0L;
try {
ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) {
timeout = INTERRUPTED;
putStat = 0;
ForkJoinPool.helpAsyncBlocker(executor, this);
if ((stat = putStat) == 0) {
try {
ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) {
timeout = INTERRUPTED;
}
stat = putStat;
}
stat = putStat;
if (timeout < 0L)
Thread.currentThread().interrupt();
}
return stat;
}
/**
* Tries helping for FJ submitter.
*/
private int internalHelpConsume(ForkJoinPool.WorkQueue w, T item) {
int stat = 0;
if (w != null) {
ForkJoinTask<?> t;
while ((t = w.peek()) != null && (t instanceof ConsumerTask)) {
if ((stat = offer(item)) != 0 || !w.tryUnpush(t))
break;
((ConsumerTask<?>)t).consumer.consume();
}
}
return stat;
}
/**
* Tries helping for non-FJ submitter.
*/
private int externalHelpConsume(ForkJoinPool.WorkQueue w, T item) {
int stat = 0;
if (w != null) {
ForkJoinTask<?> t;
while ((t = w.peek()) != null && (t instanceof ConsumerTask)) {
if ((stat = offer(item)) != 0 || !w.trySharedUnpush(t))
break;
((ConsumerTask<?>)t).consumer.consume();
}
}
return stat;
}
/**
* Timeout version; similar to submit.
*/
final int timedOffer(T item, long nanos) {
int stat; Executor e;
if ((stat = offer(item)) == 0 && helpDepth == 0 &&
((e = executor) instanceof ForkJoinPool)) {
Thread thread = Thread.currentThread();
if (((thread instanceof ForkJoinWorkerThread) &&
((ForkJoinWorkerThread)thread).getPool() == e) ||
e == ForkJoinPool.commonPool()) {
helpDepth = 1;
ForkJoinTask<?> t;
long deadline = System.nanoTime() + nanos;
while ((t = ForkJoinTask.peekNextLocalTask()) != null &&
(t instanceof ConsumerTask)) {
if ((stat = offer(item)) != 0 ||
(nanos = deadline - System.nanoTime()) <= 0L ||
!t.tryUnfork())
break;
((ConsumerTask<?>)t).consumer.consume();
}
helpDepth = 0;
}
}
if (stat == 0 && (stat = offer(item)) == 0 &&
(timeout = nanos) > 0L) {
int stat;
if ((stat = offer(item)) == 0 && (timeout = nanos) > 0L) {
putItem = item;
try {
ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) {
timeout = INTERRUPTED;
putStat = 0;
ForkJoinPool.helpAsyncBlocker(executor, this);
if ((stat = putStat) == 0) {
try {
ForkJoinPool.managedBlock(this);
} catch (InterruptedException ie) {
timeout = INTERRUPTED;
}
stat = putStat;
}
stat = putStat;
if (timeout < 0L)
Thread.currentThread().interrupt();
}
@ -1249,22 +1191,20 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
}
else if ((c & ACTIVE) != 0) { // ensure keep-alive
if ((c & CONSUME) != 0 ||
U.compareAndSwapInt(this, CTL, c,
c | CONSUME))
CTL.compareAndSet(this, c, c | CONSUME))
break;
}
else if (demand == 0L || tail == head)
break;
else if (U.compareAndSwapInt(this, CTL, c,
c | (ACTIVE | CONSUME))) {
else if (CTL.compareAndSet(this, c, c | (ACTIVE | CONSUME))) {
try {
e.execute(new ConsumerTask<T>(this));
break;
} catch (RuntimeException | Error ex) { // back out
do {} while (((c = ctl) & DISABLED) == 0 &&
(c & ACTIVE) != 0 &&
!U.compareAndSwapInt(this, CTL, c,
c & ~ACTIVE));
!CTL.weakCompareAndSetVolatile
(this, c, c & ~ACTIVE));
throw ex;
}
}
@ -1300,10 +1240,10 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
break;
else if ((c & ACTIVE) != 0) {
pendingError = ex;
if (U.compareAndSwapInt(this, CTL, c, c | ERROR))
if (CTL.compareAndSet(this, c, c | ERROR))
break; // cause consumer task to exit
}
else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
else if (CTL.compareAndSet(this, c, DISABLED)) {
Flow.Subscriber<? super T> s = subscriber;
if (s != null && ex != null) {
try {
@ -1330,7 +1270,7 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
for (int c;;) {
if ((c = ctl) == DISABLED || (c & ACTIVE) == 0)
break;
if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE)) {
if (CTL.compareAndSet(this, c, c & ~ACTIVE)) {
onError(ex);
break;
}
@ -1343,8 +1283,8 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
for (int c;;) {
if ((c = ctl) == DISABLED)
break;
if (U.compareAndSwapInt(this, CTL, c,
c | (ACTIVE | CONSUME | COMPLETE))) {
if (CTL.compareAndSet(this, c,
c | (ACTIVE | CONSUME | COMPLETE))) {
if ((c & ACTIVE) == 0)
startOrDisable();
break;
@ -1356,8 +1296,8 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
for (int c;;) {
if ((c = ctl) == DISABLED)
break;
if (U.compareAndSwapInt(this, CTL, c,
c | (ACTIVE | CONSUME | SUBSCRIBE))) {
if (CTL.compareAndSet(this, c,
c | (ACTIVE | CONSUME | SUBSCRIBE))) {
if ((c & ACTIVE) == 0)
startOrDisable();
break;
@ -1375,11 +1315,11 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
if ((c = ctl) == DISABLED)
break;
else if ((c & ACTIVE) != 0) {
if (U.compareAndSwapInt(this, CTL, c,
c | (CONSUME | ERROR)))
if (CTL.compareAndSet(this, c,
c | (CONSUME | ERROR)))
break;
}
else if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
else if (CTL.compareAndSet(this, c, DISABLED)) {
detach();
break;
}
@ -1395,19 +1335,18 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
long prev = demand, d;
if ((d = prev + n) < prev) // saturate
d = Long.MAX_VALUE;
if (U.compareAndSwapLong(this, DEMAND, prev, d)) {
if (DEMAND.compareAndSet(this, prev, d)) {
for (int c, h;;) {
if ((c = ctl) == DISABLED)
break;
else if ((c & ACTIVE) != 0) {
if ((c & CONSUME) != 0 ||
U.compareAndSwapInt(this, CTL, c,
c | CONSUME))
CTL.compareAndSet(this, c, c | CONSUME))
break;
}
else if ((h = head) != tail) {
if (U.compareAndSwapInt(this, CTL, c,
c | (ACTIVE|CONSUME))) {
if (CTL.compareAndSet(this, c,
c | (ACTIVE|CONSUME))) {
startOrDisable();
break;
}
@ -1476,16 +1415,14 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
if ((s = subscriber) != null) { // else disabled
for (;;) {
long d = demand;
int c; Object[] a; int n; long i; Object x; Thread w;
int c; Object[] a; int n, i; Object x; Thread w;
if (((c = ctl) & (ERROR | SUBSCRIBE | DISABLED)) != 0) {
if (!checkControl(s, c))
break;
}
else if ((a = array) == null || h == tail ||
(n = a.length) == 0 ||
(x = U.getObjectVolatile
(a, (i = ((long)((n - 1) & h) << ASHIFT) + ABASE)))
== null) {
(x = QA.getAcquire(a, i = (n - 1) & h)) == null) {
if (!checkEmpty(s, c))
break;
}
@ -1494,10 +1431,10 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
break;
}
else if (((c & CONSUME) != 0 ||
U.compareAndSwapInt(this, CTL, c, c | CONSUME)) &&
U.compareAndSwapObject(a, i, x, null)) {
U.putIntRelease(this, HEAD, ++h);
U.getAndAddLong(this, DEMAND, -1L);
CTL.compareAndSet(this, c, c | CONSUME)) &&
QA.compareAndSet(a, i, x, null)) {
HEAD.setRelease(this, ++h);
DEMAND.getAndAdd(this, -1L);
if ((w = waiter) != null)
signalWaiter(w);
try {
@ -1528,7 +1465,7 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
}
}
else if ((c & SUBSCRIBE) != 0) {
if (U.compareAndSwapInt(this, CTL, c, c & ~SUBSCRIBE)) {
if (CTL.compareAndSet(this, c, c & ~SUBSCRIBE)) {
try {
if (s != null)
s.onSubscribe(this);
@ -1551,9 +1488,9 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
boolean stat = true;
if (head == tail) {
if ((c & CONSUME) != 0)
U.compareAndSwapInt(this, CTL, c, c & ~CONSUME);
CTL.compareAndSet(this, c, c & ~CONSUME);
else if ((c & COMPLETE) != 0) {
if (U.compareAndSwapInt(this, CTL, c, DISABLED)) {
if (CTL.compareAndSet(this, c, DISABLED)) {
try {
if (s != null)
s.onComplete();
@ -1561,7 +1498,7 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
}
}
}
else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE))
else if (CTL.compareAndSet(this, c, c & ~ACTIVE))
stat = false;
}
return stat;
@ -1574,8 +1511,8 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
boolean stat = true;
if (demand == 0L) {
if ((c & CONSUME) != 0)
U.compareAndSwapInt(this, CTL, c, c & ~CONSUME);
else if (U.compareAndSwapInt(this, CTL, c, c & ~ACTIVE))
CTL.compareAndSet(this, c, c & ~CONSUME);
else if (CTL.compareAndSet(this, c, c & ~ACTIVE))
stat = false;
}
return stat;
@ -1595,31 +1532,25 @@ public class SubmissionPublisher<T> implements Flow.Publisher<T>,
onError(ex);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long CTL;
private static final long TAIL;
private static final long HEAD;
private static final long DEMAND;
private static final int ABASE;
private static final int ASHIFT;
// VarHandle mechanics
private static final VarHandle CTL;
private static final VarHandle TAIL;
private static final VarHandle HEAD;
private static final VarHandle DEMAND;
private static final VarHandle QA;
static {
try {
CTL = U.objectFieldOffset
(BufferedSubscription.class.getDeclaredField("ctl"));
TAIL = U.objectFieldOffset
(BufferedSubscription.class.getDeclaredField("tail"));
HEAD = U.objectFieldOffset
(BufferedSubscription.class.getDeclaredField("head"));
DEMAND = U.objectFieldOffset
(BufferedSubscription.class.getDeclaredField("demand"));
ABASE = U.arrayBaseOffset(Object[].class);
int scale = U.arrayIndexScale(Object[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
MethodHandles.Lookup l = MethodHandles.lookup();
CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
int.class);
TAIL = l.findVarHandle(BufferedSubscription.class, "tail",
int.class);
HEAD = l.findVarHandle(BufferedSubscription.class, "head",
int.class);
DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
long.class);
QA = MethodHandles.arrayElementVarHandle(Object[].class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -36,6 +36,8 @@
package java.util.concurrent;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Collections;
@ -247,7 +249,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
U.compareAndSwapObject(this, NEXT, cmp, val);
SNEXT.compareAndSet(this, cmp, val);
}
/**
@ -260,7 +262,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
boolean tryMatch(SNode s) {
if (match == null &&
U.compareAndSwapObject(this, MATCH, null, s)) {
SMATCH.compareAndSet(this, null, s)) {
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
@ -275,24 +277,21 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* Tries to cancel a wait by matching node to itself.
*/
void tryCancel() {
U.compareAndSwapObject(this, MATCH, null, this);
SMATCH.compareAndSet(this, null, this);
}
boolean isCancelled() {
return match == this;
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long MATCH;
private static final long NEXT;
// VarHandle mechanics
private static final VarHandle SMATCH;
private static final VarHandle SNEXT;
static {
try {
MATCH = U.objectFieldOffset
(SNode.class.getDeclaredField("match"));
NEXT = U.objectFieldOffset
(SNode.class.getDeclaredField("next"));
MethodHandles.Lookup l = MethodHandles.lookup();
SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -304,7 +303,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean casHead(SNode h, SNode nh) {
return h == head &&
U.compareAndSwapObject(this, HEAD, h, nh);
SHEAD.compareAndSet(this, h, nh);
}
/**
@ -451,8 +450,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
continue;
}
}
if (spins > 0)
if (spins > 0) {
Thread.onSpinWait();
spins = shouldSpin(s) ? (spins - 1) : 0;
}
else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter
else if (!timed)
@ -508,13 +509,12 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
// VarHandle mechanics
private static final VarHandle SHEAD;
static {
try {
HEAD = U.objectFieldOffset
(TransferStack.class.getDeclaredField("head"));
MethodHandles.Lookup l = MethodHandles.lookup();
SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -546,19 +546,19 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
U.compareAndSwapObject(this, NEXT, cmp, val);
QNEXT.compareAndSet(this, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
U.compareAndSwapObject(this, ITEM, cmp, val);
QITEM.compareAndSet(this, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
U.compareAndSwapObject(this, ITEM, cmp, this);
QITEM.compareAndSet(this, cmp, this);
}
boolean isCancelled() {
@ -574,17 +574,14 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
return next == this;
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long ITEM;
private static final long NEXT;
// VarHandle mechanics
private static final VarHandle QITEM;
private static final VarHandle QNEXT;
static {
try {
ITEM = U.objectFieldOffset
(QNode.class.getDeclaredField("item"));
NEXT = U.objectFieldOffset
(QNode.class.getDeclaredField("next"));
MethodHandles.Lookup l = MethodHandles.lookup();
QITEM = l.findVarHandle(QNode.class, "item", Object.class);
QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -614,7 +611,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
void advanceHead(QNode h, QNode nh) {
if (h == head &&
U.compareAndSwapObject(this, HEAD, h, nh))
QHEAD.compareAndSet(this, h, nh))
h.next = h; // forget old next
}
@ -623,7 +620,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
void advanceTail(QNode t, QNode nt) {
if (tail == t)
U.compareAndSwapObject(this, TAIL, t, nt);
QTAIL.compareAndSet(this, t, nt);
}
/**
@ -631,7 +628,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
U.compareAndSwapObject(this, CLEANME, cmp, val);
QCLEANME.compareAndSet(this, cmp, val);
}
/**
@ -752,8 +749,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
continue;
}
}
if (spins > 0)
if (spins > 0) {
--spins;
Thread.onSpinWait();
}
else if (s.waiter == null)
s.waiter = w;
else if (!timed)
@ -817,18 +816,19 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
}
}
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long HEAD;
private static final long TAIL;
private static final long CLEANME;
// VarHandle mechanics
private static final VarHandle QHEAD;
private static final VarHandle QTAIL;
private static final VarHandle QCLEANME;
static {
try {
HEAD = U.objectFieldOffset
(TransferQueue.class.getDeclaredField("head"));
TAIL = U.objectFieldOffset
(TransferQueue.class.getDeclaredField("tail"));
CLEANME = U.objectFieldOffset
(TransferQueue.class.getDeclaredField("cleanMe"));
MethodHandles.Lookup l = MethodHandles.lookup();
QHEAD = l.findVarHandle(TransferQueue.class, "head",
QNode.class);
QTAIL = l.findVarHandle(TransferQueue.class, "tail",
QNode.class);
QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
QNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -36,6 +36,7 @@
package java.util.concurrent;
import java.io.ObjectStreamField;
import java.security.AccessControlContext;
import java.util.Random;
import java.util.Spliterator;
import java.util.concurrent.atomic.AtomicInteger;
@ -47,6 +48,7 @@ import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.StreamSupport;
import jdk.internal.misc.Unsafe;
/**
* A random number generator isolated to the current thread. Like the
@ -95,7 +97,9 @@ public class ThreadLocalRandom extends Random {
* ThreadLocalRandom sequence. The dual use is a marriage of
* convenience, but is a simple and efficient way of reducing
* application-level overhead and footprint of most concurrent
* programs.
* programs. Even more opportunistically, we also define here
* other package-private utilities that access Thread class
* fields.
*
* Even though this class subclasses java.util.Random, it uses the
* same basic algorithm as java.util.SplittableRandom. (See its
@ -958,6 +962,49 @@ public class ThreadLocalRandom extends Random {
return r;
}
// Support for other package-private ThreadLocal access
/**
* Erases ThreadLocals by nulling out Thread maps.
*/
static final void eraseThreadLocals(Thread thread) {
U.putObject(thread, THREADLOCALS, null);
U.putObject(thread, INHERITABLETHREADLOCALS, null);
}
static final void setInheritedAccessControlContext(Thread thread,
AccessControlContext acc) {
U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
}
/**
* Returns a new group with the system ThreadGroup (the
* topmost, parent-less group) as parent. Uses Unsafe to
* traverse Thread.group and ThreadGroup.parent fields.
*/
static final ThreadGroup createThreadGroup(String name) {
if (name == null)
throw new NullPointerException();
try {
long tg = U.objectFieldOffset
(Thread.class.getDeclaredField("group"));
long gp = U.objectFieldOffset
(ThreadGroup.class.getDeclaredField("parent"));
ThreadGroup group = (ThreadGroup)
U.getObject(Thread.currentThread(), tg);
while (group != null) {
ThreadGroup parent = (ThreadGroup)U.getObject(group, gp);
if (parent == null)
return new ThreadGroup(group, name);
group = parent;
}
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
// fall through if null as cannot-happen safeguard
throw new Error("Cannot create ThreadGroup");
}
// Serialization support
private static final long serialVersionUID = -5851777807851030925L;
@ -1022,10 +1069,13 @@ public class ThreadLocalRandom extends Random {
static final String BAD_SIZE = "size must be non-negative";
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private static final long SEED;
private static final long PROBE;
private static final long SECONDARY;
private static final long THREADLOCALS;
private static final long INHERITABLETHREADLOCALS;
private static final long INHERITEDACCESSCONTROLCONTEXT;
static {
try {
SEED = U.objectFieldOffset
@ -1034,6 +1084,12 @@ public class ThreadLocalRandom extends Random {
(Thread.class.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
THREADLOCALS = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocals"));
INHERITABLETHREADLOCALS = U.objectFieldOffset
(Thread.class.getDeclaredField("inheritableThreadLocals"));
INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
(Thread.class.getDeclaredField("inheritedAccessControlContext"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -35,27 +35,26 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* A {@code boolean} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for
* description of the properties of atomic variables. An
* {@code AtomicBoolean} is used in applications such as atomically
* updated flags, and cannot be used as a replacement for a
* {@link java.lang.Boolean}.
* {@link VarHandle} specification for descriptions of the properties
* of atomic accesses. An {@code AtomicBoolean} is used in
* applications such as atomically updated flags, and cannot be used
* as a replacement for a {@link java.lang.Boolean}.
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicBoolean implements java.io.Serializable {
private static final long serialVersionUID = 4654671469794556979L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE;
private static final VarHandle VALUE;
static {
try {
VALUE = U.objectFieldOffset
(AtomicBoolean.class.getDeclaredField("value"));
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -79,7 +78,8 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
* Returns the current value.
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@ -88,40 +88,39 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(boolean expect, boolean update) {
return U.compareAndSwapInt(this, VALUE,
(expect ? 1 : 0),
(update ? 1 : 0));
public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
return VALUE.compareAndSet(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0));
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public boolean weakCompareAndSet(boolean expect, boolean update) {
return U.compareAndSwapInt(this, VALUE,
(expect ? 1 : 0),
(update ? 1 : 0));
public boolean weakCompareAndSet(boolean expectedValue, boolean newValue) {
return VALUE.weakCompareAndSet(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0));
}
/**
* Unconditionally sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
@ -130,17 +129,19 @@ public class AtomicBoolean implements java.io.Serializable {
}
/**
* Eventually sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(boolean newValue) {
U.putIntRelease(this, VALUE, (newValue ? 1 : 0));
VALUE.setRelease(this, (newValue ? 1 : 0));
}
/**
* Atomically sets to the given value and returns the previous value.
* Atomically sets the value to {@code newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
@ -161,4 +162,178 @@ public class AtomicBoolean implements java.io.Serializable {
return Boolean.toString(get());
}
// jdk9
/**
* Returns the current value, with memory semantics of reading as
* if the variable was declared non-{@code volatile}.
*
* @return the value
* @since 9
*/
public final boolean getPlain() {
return (int)VALUE.get(this) != 0;
}
/**
* Sets the value to {@code newValue}, with memory semantics
* of setting as if the variable was declared non-{@code volatile}
* and non-{@code final}.
*
* @param newValue the new value
* @since 9
*/
public final void setPlain(boolean newValue) {
VALUE.set(this, newValue ? 1 : 0);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @return the value
* @since 9
*/
public final boolean getOpaque() {
return (int)VALUE.getOpaque(this) != 0;
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param newValue the new value
* @since 9
*/
public final void setOpaque(boolean newValue) {
VALUE.setOpaque(this, newValue ? 1 : 0);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @return the value
* @since 9
*/
public final boolean getAcquire() {
return (int)VALUE.getAcquire(this) != 0;
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 9
*/
public final void setRelease(boolean newValue) {
VALUE.setRelease(this, newValue ? 1 : 0);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final boolean compareAndExchange(boolean expectedValue, boolean newValue) {
return (int)VALUE.compareAndExchange(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0)) != 0;
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final boolean compareAndExchangeAcquire(boolean expectedValue, boolean newValue) {
return (int)VALUE.compareAndExchangeAcquire(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0)) != 0;
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final boolean compareAndExchangeRelease(boolean expectedValue, boolean newValue) {
return (int)VALUE.compareAndExchangeRelease(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0)) != 0;
}
/**
* Possibly atomically sets the value to {@code newValue} if the current
* value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(boolean expectedValue, boolean newValue) {
return VALUE.weakCompareAndSetVolatile(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0));
}
/**
* Possibly atomically sets the value to {@code newValue} if the current
* value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(boolean expectedValue, boolean newValue) {
return VALUE.weakCompareAndSetAcquire(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0));
}
/**
* Possibly atomically sets the value to {@code newValue} if the current
* value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(boolean expectedValue, boolean newValue) {
return VALUE.weakCompareAndSetRelease(this,
(expectedValue ? 1 : 0),
(newValue ? 1 : 0));
}
}

View File

@ -35,32 +35,30 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
/**
* An {@code int} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for
* description of the properties of atomic variables. An
* {@code AtomicInteger} is used in applications such as atomically
* incremented counters, and cannot be used as a replacement for an
* {@link java.lang.Integer}. However, this class does extend
* {@code Number} to allow uniform access by tools and utilities that
* deal with numerically-based classes.
* {@link VarHandle} specification for descriptions of the properties
* of atomic accesses. An {@code AtomicInteger} is used in
* applications such as atomically incremented counters, and cannot be
* used as a replacement for an {@link java.lang.Integer}. However,
* this class does extend {@code Number} to allow uniform access by
* tools and utilities that deal with numerically-based classes.
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE;
private static final VarHandle VALUE;
static {
try {
VALUE = U.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicInteger.class, "value", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -84,7 +82,8 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Gets the current value.
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@ -93,7 +92,8 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
@ -102,108 +102,122 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Eventually sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int newValue) {
U.putIntRelease(this, VALUE, newValue);
VALUE.setRelease(this, newValue);
}
/**
* Atomically sets to the given value and returns the old value.
* Atomically sets the value to {@code newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int newValue) {
return U.getAndSetInt(this, VALUE, newValue);
return (int)VALUE.getAndSet(this, newValue);
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return U.compareAndSwapInt(this, VALUE, expect, update);
public final boolean compareAndSet(int expectedValue, int newValue) {
return VALUE.compareAndSet(this, expectedValue, newValue);
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(int expect, int update) {
return U.compareAndSwapInt(this, VALUE, expect, update);
public final boolean weakCompareAndSet(int expectedValue, int newValue) {
return VALUE.weakCompareAndSet(this, expectedValue, newValue);
}
/**
* Atomically increments by one the current value.
* Atomically increments the current value,
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(1)}.
*
* @return the previous value
*/
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
return (int)VALUE.getAndAdd(this, 1);
}
/**
* Atomically decrements by one the current value.
* Atomically decrements the current value,
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(-1)}.
*
* @return the previous value
*/
public final int getAndDecrement() {
return U.getAndAddInt(this, VALUE, -1);
return (int)VALUE.getAndAdd(this, -1);
}
/**
* Atomically adds the given value to the current value.
* Atomically adds the given value to the current value,
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
return U.getAndAddInt(this, VALUE, delta);
return (int)VALUE.getAndAdd(this, delta);
}
/**
* Atomically increments by one the current value.
* Atomically increments the current value,
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(1)}.
*
* @return the updated value
*/
public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
return (int)VALUE.addAndGet(this, 1);
}
/**
* Atomically decrements by one the current value.
* Atomically decrements the current value,
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(-1)}.
*
* @return the updated value
*/
public final int decrementAndGet() {
return U.getAndAddInt(this, VALUE, -1) - 1;
return (int)VALUE.addAndGet(this, -1);
}
/**
* Atomically adds the given value to the current value.
* Atomically adds the given value to the current value,
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int delta) {
return U.getAndAddInt(this, VALUE, delta) + delta;
return (int)VALUE.addAndGet(this, delta);
}
/**
@ -217,12 +231,14 @@ public class AtomicInteger extends Number implements java.io.Serializable {
* @since 1.8
*/
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return prev;
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
/**
@ -236,12 +252,14 @@ public class AtomicInteger extends Number implements java.io.Serializable {
* @since 1.8
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
/**
@ -260,12 +278,14 @@ public class AtomicInteger extends Number implements java.io.Serializable {
*/
public final int getAndAccumulate(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return prev;
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsInt(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
/**
@ -284,12 +304,14 @@ public class AtomicInteger extends Number implements java.io.Serializable {
*/
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSet(prev, next));
return next;
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsInt(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
/**
@ -301,7 +323,10 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicInteger} as an {@code int}.
* Returns the current value of this {@code AtomicInteger} as an
* {@code int},
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* Equivalent to {@link #get()}.
*/
public int intValue() {
@ -309,8 +334,9 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicInteger} as a {@code long}
* after a widening primitive conversion.
* Returns the current value of this {@code AtomicInteger} as a
* {@code long} after a widening primitive conversion,
* with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public long longValue() {
@ -318,8 +344,9 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicInteger} as a {@code float}
* after a widening primitive conversion.
* Returns the current value of this {@code AtomicInteger} as a
* {@code float} after a widening primitive conversion,
* with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public float floatValue() {
@ -327,12 +354,175 @@ public class AtomicInteger extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicInteger} as a {@code double}
* after a widening primitive conversion.
* Returns the current value of this {@code AtomicInteger} as a
* {@code double} after a widening primitive conversion,
* with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)get();
}
// jdk9
/**
* Returns the current value, with memory semantics of reading as
* if the variable was declared non-{@code volatile}.
*
* @return the value
* @since 9
*/
public final int getPlain() {
return (int)VALUE.get(this);
}
/**
* Sets the value to {@code newValue}, with memory semantics
* of setting as if the variable was declared non-{@code volatile}
* and non-{@code final}.
*
* @param newValue the new value
* @since 9
*/
public final void setPlain(int newValue) {
VALUE.set(this, newValue);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @return the value
* @since 9
*/
public final int getOpaque() {
return (int)VALUE.getOpaque(this);
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param newValue the new value
* @since 9
*/
public final void setOpaque(int newValue) {
VALUE.setOpaque(this, newValue);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @return the value
* @since 9
*/
public final int getAcquire() {
return (int)VALUE.getAcquire(this);
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 9
*/
public final void setRelease(int newValue) {
VALUE.setRelease(this, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final int compareAndExchange(int expectedValue, int newValue) {
return (int)VALUE.compareAndExchange(this, expectedValue, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final int compareAndExchangeAcquire(int expectedValue, int newValue) {
return (int)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final int compareAndExchangeRelease(int expectedValue, int newValue) {
return (int)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue} if
* the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(int expectedValue, int newValue) {
return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue} if
* the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(int expectedValue, int newValue) {
return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue} if
* the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(int expectedValue, int newValue) {
return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
}
}

View File

@ -35,44 +35,24 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
/**
* An {@code int} array in which elements may be updated atomically.
* See the {@link java.util.concurrent.atomic} package
* specification for description of the properties of atomic
* variables.
* See the {@link VarHandle} specification for descriptions of the
* properties of atomic accesses.
* @since 1.5
* @author Doug Lea
*/
public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final int ABASE;
private static final int ASHIFT;
private static final VarHandle AA
= MethodHandles.arrayElementVarHandle(int[].class);
private final int[] array;
static {
ABASE = U.arrayBaseOffset(int[].class);
int scale = U.arrayIndexScale(int[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("array index scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << ASHIFT) + ABASE;
}
/**
* Creates a new AtomicIntegerArray of the given length, with all
* elements initially zero.
@ -105,147 +85,155 @@ public class AtomicIntegerArray implements java.io.Serializable {
}
/**
* Gets the current value at position {@code i}.
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @param i the index
* @return the current value
*/
public final int get(int i) {
return getRaw(checkedByteOffset(i));
}
private int getRaw(long offset) {
return U.getIntVolatile(array, offset);
return (int)AA.getVolatile(array, i);
}
/**
* Sets the element at position {@code i} to the given value.
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param i the index
* @param newValue the new value
*/
public final void set(int i, int newValue) {
U.putIntVolatile(array, checkedByteOffset(i), newValue);
AA.setVolatile(array, i, newValue);
}
/**
* Eventually sets the element at position {@code i} to the given value.
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int i, int newValue) {
U.putIntRelease(array, checkedByteOffset(i), newValue);
AA.setRelease(array, i, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* value and returns the old value.
* Atomically sets the element at index {@code i} to {@code
* newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param i the index
* @param newValue the new value
* @return the previous value
*/
public final int getAndSet(int i, int newValue) {
return U.getAndSetInt(array, checkedByteOffset(i), newValue);
return (int)AA.getAndSet(array, i, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
* Atomically sets the element at index {@code i} to {@code
* newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int i, int expect, int update) {
return compareAndSetRaw(checkedByteOffset(i), expect, update);
}
private boolean compareAndSetRaw(long offset, int expect, int update) {
return U.compareAndSwapInt(array, offset, expect, update);
public final boolean compareAndSet(int i, int expectedValue, int newValue) {
return AA.compareAndSet(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(int i, int expect, int update) {
return compareAndSet(i, expect, update);
public final boolean weakCompareAndSet(int i, int expectedValue, int newValue) {
return AA.weakCompareAndSet(array, i, expectedValue, newValue);
}
/**
* Atomically increments by one the element at index {@code i}.
* Atomically increments the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(i, 1)}.
*
* @param i the index
* @return the previous value
*/
public final int getAndIncrement(int i) {
return getAndAdd(i, 1);
return (int)AA.getAndAdd(array, i, 1);
}
/**
* Atomically decrements by one the element at index {@code i}.
* Atomically decrements the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(i, -1)}.
*
* @param i the index
* @return the previous value
*/
public final int getAndDecrement(int i) {
return getAndAdd(i, -1);
return (int)AA.getAndAdd(array, i, -1);
}
/**
* Atomically adds the given value to the element at index {@code i}.
* Atomically adds the given value to the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param i the index
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int i, int delta) {
return U.getAndAddInt(array, checkedByteOffset(i), delta);
return (int)AA.getAndAdd(array, i, delta);
}
/**
* Atomically increments by one the element at index {@code i}.
* Atomically increments the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(i, 1)}.
*
* @param i the index
* @return the updated value
*/
public final int incrementAndGet(int i) {
return getAndAdd(i, 1) + 1;
return (int)AA.addAndGet(array, i, 1);
}
/**
* Atomically decrements by one the element at index {@code i}.
* Atomically decrements the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(i, -1)}.
*
* @param i the index
* @return the updated value
*/
public final int decrementAndGet(int i) {
return getAndAdd(i, -1) - 1;
return (int)AA.addAndGet(array, i, -1);
}
/**
* Atomically adds the given value to the element at index {@code i}.
* Atomically adds the given value to the element at index {@code i},
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param i the index
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int i, int delta) {
return getAndAdd(i, delta) + delta;
return (int)AA.addAndGet(array, i, delta);
}
/**
@ -260,13 +248,14 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @since 1.8
*/
public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = updateFunction.applyAsInt(prev);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
int prev = get(i), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(i, prev, next))
return prev;
haveNext = (prev == (prev = get(i)));
}
}
/**
@ -281,23 +270,25 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @since 1.8
*/
public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = updateFunction.applyAsInt(prev);
} while (!compareAndSetRaw(offset, prev, next));
return next;
int prev = get(i), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(i, prev, next))
return next;
haveNext = (prev == (prev = get(i)));
}
}
/**
* Atomically updates the element at index {@code i} with the
* results of applying the given function to the current and
* given values, returning the previous value. The function should
* be side-effect-free, since it may be re-applied when attempted
* results of applying the given function to the current and given
* values, returning the previous value. The function should be
* side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
* applied with the current value at index {@code i} as its first
* argument, and the given update as the second argument.
* applied with the current value of the element at index {@code i}
* as its first argument, and the given update as the second
* argument.
*
* @param i the index
* @param x the update value
@ -307,23 +298,25 @@ public class AtomicIntegerArray implements java.io.Serializable {
*/
public final int getAndAccumulate(int i, int x,
IntBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
int prev = get(i), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsInt(prev, x);
if (weakCompareAndSetVolatile(i, prev, next))
return prev;
haveNext = (prev == (prev = get(i)));
}
}
/**
* Atomically updates the element at index {@code i} with the
* results of applying the given function to the current and
* given values, returning the updated value. The function should
* be side-effect-free, since it may be re-applied when attempted
* results of applying the given function to the current and given
* values, returning the updated value. The function should be
* side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
* applied with the current value at index {@code i} as its first
* argument, and the given update as the second argument.
* applied with the current value of the element at index {@code i}
* as its first argument, and the given update as the second
* argument.
*
* @param i the index
* @param x the update value
@ -333,13 +326,14 @@ public class AtomicIntegerArray implements java.io.Serializable {
*/
public final int accumulateAndGet(int i, int x,
IntBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
int prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.applyAsInt(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return next;
int prev = get(i), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsInt(prev, x);
if (weakCompareAndSetVolatile(i, prev, next))
return next;
haveNext = (prev == (prev = get(i)));
}
}
/**
@ -354,11 +348,190 @@ public class AtomicIntegerArray implements java.io.Serializable {
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
b.append(get(i));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
}
// jdk9
/**
* Returns the current value of the element at index {@code i},
* with memory semantics of reading as if the variable was declared
* non-{@code volatile}.
*
* @param i the index
* @return the value
* @since 9
*/
public final int getPlain(int i) {
return (int)AA.get(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory semantics of setting as if the variable was
* declared non-{@code volatile} and non-{@code final}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setPlain(int i, int newValue) {
AA.set(array, i, newValue);
}
/**
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @param i the index
* @return the value
* @since 9
*/
public final int getOpaque(int i) {
return (int)AA.getOpaque(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setOpaque(int i, int newValue) {
AA.setOpaque(array, i, newValue);
}
/**
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @param i the index
* @return the value
* @since 9
*/
public final int getAcquire(int i) {
return (int)AA.getAcquire(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setRelease(int i, int newValue) {
AA.setRelease(array, i, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final int compareAndExchange(int i, int expectedValue, int newValue) {
return (int)AA.compareAndExchange(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final int compareAndExchangeAcquire(int i, int expectedValue, int newValue) {
return (int)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final int compareAndExchangeRelease(int i, int expectedValue, int newValue) {
return (int)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(int i, int expectedValue, int newValue) {
return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(int i, int expectedValue, int newValue) {
return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(int i, int expectedValue, int newValue) {
return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
}
}

View File

@ -42,6 +42,7 @@ import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.function.IntBinaryOperator;
import java.util.function.IntUnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@ -150,8 +151,8 @@ public abstract class AtomicIntegerFieldUpdater<T> {
public abstract void lazySet(T obj, int newValue);
/**
* Gets the current value held in the field of the given object managed
* by this updater.
* Returns the current value held in the field of the given object
* managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@ -367,7 +368,7 @@ public abstract class AtomicIntegerFieldUpdater<T> {
*/
private static final class AtomicIntegerFieldUpdaterImpl<T>
extends AtomicIntegerFieldUpdater<T> {
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else

View File

@ -35,31 +35,30 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
/**
* A {@code long} value that may be updated atomically. See the
* {@link java.util.concurrent.atomic} package specification for
* description of the properties of atomic variables. An
* {@code AtomicLong} is used in applications such as atomically
* incremented sequence numbers, and cannot be used as a replacement
* for a {@link java.lang.Long}. However, this class does extend
* {@code Number} to allow uniform access by tools and utilities that
* deal with numerically-based classes.
* {@link VarHandle} specification for descriptions of the properties
* of atomic accesses. An {@code AtomicLong} is used in applications
* such as atomically incremented sequence numbers, and cannot be used
* as a replacement for a {@link java.lang.Long}. However, this class
* does extend {@code Number} to allow uniform access by tools and
* utilities that deal with numerically-based classes.
*
* @since 1.5
* @author Doug Lea
*/
public class AtomicLong extends Number implements java.io.Serializable {
private static final long serialVersionUID = 1927816293512124184L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE;
private static final VarHandle VALUE;
/**
* Records whether the underlying JVM supports lockless
* compareAndSwap for longs. While the Unsafe.compareAndSwapLong
* compareAndSwap for longs. While the intrinsic compareAndSwapLong
* method works in either case, some constructions should be
* handled at Java level to avoid locking user-visible locks.
*/
@ -73,8 +72,8 @@ public class AtomicLong extends Number implements java.io.Serializable {
static {
try {
VALUE = U.objectFieldOffset
(AtomicLong.class.getDeclaredField("value"));
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicLong.class, "value", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -98,7 +97,8 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* Gets the current value.
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@ -107,119 +107,132 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* Sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
public final void set(long newValue) {
// Use putLongVolatile instead of ordinary volatile store when
// using compareAndSwapLong, for sake of some 32bit systems.
U.putLongVolatile(this, VALUE, newValue);
VALUE.setVolatile(this, newValue);
}
/**
* Eventually sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(long newValue) {
U.putLongRelease(this, VALUE, newValue);
VALUE.setRelease(this, newValue);
}
/**
* Atomically sets to the given value and returns the old value.
* Atomically sets the value to {@code newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
*/
public final long getAndSet(long newValue) {
return U.getAndSetLong(this, VALUE, newValue);
return (long)VALUE.getAndSet(this, newValue);
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(long expect, long update) {
return U.compareAndSwapLong(this, VALUE, expect, update);
public final boolean compareAndSet(long expectedValue, long newValue) {
return VALUE.compareAndSet(this, expectedValue, newValue);
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(long expect, long update) {
return U.compareAndSwapLong(this, VALUE, expect, update);
public final boolean weakCompareAndSet(long expectedValue, long newValue) {
return VALUE.weakCompareAndSet(this, expectedValue, newValue);
}
/**
* Atomically increments by one the current value.
* Atomically increments the current value,
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(1)}.
*
* @return the previous value
*/
public final long getAndIncrement() {
return U.getAndAddLong(this, VALUE, 1L);
return (long)VALUE.getAndAdd(this, 1L);
}
/**
* Atomically decrements by one the current value.
* Atomically decrements the current value,
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(-1)}.
*
* @return the previous value
*/
public final long getAndDecrement() {
return U.getAndAddLong(this, VALUE, -1L);
return (long)VALUE.getAndAdd(this, -1L);
}
/**
* Atomically adds the given value to the current value.
* Atomically adds the given value to the current value,
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param delta the value to add
* @return the previous value
*/
public final long getAndAdd(long delta) {
return U.getAndAddLong(this, VALUE, delta);
return (long)VALUE.getAndAdd(this, delta);
}
/**
* Atomically increments by one the current value.
* Atomically increments the current value,
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(1)}.
*
* @return the updated value
*/
public final long incrementAndGet() {
return U.getAndAddLong(this, VALUE, 1L) + 1L;
return (long)VALUE.addAndGet(this, 1L);
}
/**
* Atomically decrements by one the current value.
* Atomically decrements the current value,
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(-1)}.
*
* @return the updated value
*/
public final long decrementAndGet() {
return U.getAndAddLong(this, VALUE, -1L) - 1L;
return (long)VALUE.addAndGet(this, -1L);
}
/**
* Atomically adds the given value to the current value.
* Atomically adds the given value to the current value,
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param delta the value to add
* @return the updated value
*/
public final long addAndGet(long delta) {
return U.getAndAddLong(this, VALUE, delta) + delta;
return (long)VALUE.addAndGet(this, delta);
}
/**
@ -233,12 +246,14 @@ public class AtomicLong extends Number implements java.io.Serializable {
* @since 1.8
*/
public final long getAndUpdate(LongUnaryOperator updateFunction) {
long prev, next;
do {
prev = get();
next = updateFunction.applyAsLong(prev);
} while (!compareAndSet(prev, next));
return prev;
long prev = get(), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsLong(prev);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
/**
@ -252,12 +267,14 @@ public class AtomicLong extends Number implements java.io.Serializable {
* @since 1.8
*/
public final long updateAndGet(LongUnaryOperator updateFunction) {
long prev, next;
do {
prev = get();
next = updateFunction.applyAsLong(prev);
} while (!compareAndSet(prev, next));
return next;
long prev = get(), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsLong(prev);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
/**
@ -276,12 +293,14 @@ public class AtomicLong extends Number implements java.io.Serializable {
*/
public final long getAndAccumulate(long x,
LongBinaryOperator accumulatorFunction) {
long prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsLong(prev, x);
} while (!compareAndSet(prev, next));
return prev;
long prev = get(), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsLong(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
/**
@ -300,12 +319,14 @@ public class AtomicLong extends Number implements java.io.Serializable {
*/
public final long accumulateAndGet(long x,
LongBinaryOperator accumulatorFunction) {
long prev, next;
do {
prev = get();
next = accumulatorFunction.applyAsLong(prev, x);
} while (!compareAndSet(prev, next));
return next;
long prev = get(), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsLong(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
/**
@ -317,8 +338,9 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicLong} as an {@code int}
* after a narrowing primitive conversion.
* Returns the current value of this {@code AtomicLong} as an {@code int}
* after a narrowing primitive conversion,
* with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.3 Narrowing Primitive Conversions
*/
public int intValue() {
@ -326,7 +348,8 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicLong} as a {@code long}.
* Returns the current value of this {@code AtomicLong} as a {@code long},
* with memory effects as specified by {@link VarHandle#getVolatile}.
* Equivalent to {@link #get()}.
*/
public long longValue() {
@ -334,8 +357,9 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicLong} as a {@code float}
* after a widening primitive conversion.
* Returns the current value of this {@code AtomicLong} as a {@code float}
* after a widening primitive conversion,
* with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public float floatValue() {
@ -343,12 +367,175 @@ public class AtomicLong extends Number implements java.io.Serializable {
}
/**
* Returns the value of this {@code AtomicLong} as a {@code double}
* after a widening primitive conversion.
* Returns the current value of this {@code AtomicLong} as a {@code double}
* after a widening primitive conversion,
* with memory effects as specified by {@link VarHandle#getVolatile}.
* @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)get();
}
// jdk9
/**
* Returns the current value, with memory semantics of reading as if the
* variable was declared non-{@code volatile}.
*
* @return the value
* @since 9
*/
public final long getPlain() {
return (long)VALUE.get(this);
}
/**
* Sets the value to {@code newValue}, with memory semantics
* of setting as if the variable was declared non-{@code volatile}
* and non-{@code final}.
*
* @param newValue the new value
* @since 9
*/
public final void setPlain(long newValue) {
VALUE.set(this, newValue);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @return the value
* @since 9
*/
public final long getOpaque() {
return (long)VALUE.getOpaque(this);
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param newValue the new value
* @since 9
*/
public final void setOpaque(long newValue) {
VALUE.setOpaque(this, newValue);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @return the value
* @since 9
*/
public final long getAcquire() {
return (long)VALUE.getAcquire(this);
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 9
*/
public final void setRelease(long newValue) {
VALUE.setRelease(this, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final long compareAndExchange(long expectedValue, long newValue) {
return (long)VALUE.compareAndExchange(this, expectedValue, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final long compareAndExchangeAcquire(long expectedValue, long newValue) {
return (long)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final long compareAndExchangeRelease(long expectedValue, long newValue) {
return (long)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(long expectedValue, long newValue) {
return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(long expectedValue, long newValue) {
return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(long expectedValue, long newValue) {
return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
}
}

View File

@ -35,43 +35,24 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
/**
* A {@code long} array in which elements may be updated atomically.
* See the {@link java.util.concurrent.atomic} package specification
* for description of the properties of atomic variables.
* See the {@link VarHandle} specification for descriptions of the
* properties of atomic accesses.
* @since 1.5
* @author Doug Lea
*/
public class AtomicLongArray implements java.io.Serializable {
private static final long serialVersionUID = -2308431214976778248L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final int ABASE;
private static final int ASHIFT;
private static final VarHandle AA
= MethodHandles.arrayElementVarHandle(long[].class);
private final long[] array;
static {
ABASE = U.arrayBaseOffset(long[].class);
int scale = U.arrayIndexScale(long[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("array index scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << ASHIFT) + ABASE;
}
/**
* Creates a new AtomicLongArray of the given length, with all
* elements initially zero.
@ -104,147 +85,155 @@ public class AtomicLongArray implements java.io.Serializable {
}
/**
* Gets the current value at position {@code i}.
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @param i the index
* @return the current value
*/
public final long get(int i) {
return getRaw(checkedByteOffset(i));
}
private long getRaw(long offset) {
return U.getLongVolatile(array, offset);
return (long)AA.getVolatile(array, i);
}
/**
* Sets the element at position {@code i} to the given value.
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param i the index
* @param newValue the new value
*/
public final void set(int i, long newValue) {
U.putLongVolatile(array, checkedByteOffset(i), newValue);
AA.setVolatile(array, i, newValue);
}
/**
* Eventually sets the element at position {@code i} to the given value.
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int i, long newValue) {
U.putLongRelease(array, checkedByteOffset(i), newValue);
AA.setRelease(array, i, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given value
* and returns the old value.
* Atomically sets the element at index {@code i} to {@code
* newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param i the index
* @param newValue the new value
* @return the previous value
*/
public final long getAndSet(int i, long newValue) {
return U.getAndSetLong(array, checkedByteOffset(i), newValue);
return (long)AA.getAndSet(array, i, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int i, long expect, long update) {
return compareAndSetRaw(checkedByteOffset(i), expect, update);
}
private boolean compareAndSetRaw(long offset, long expect, long update) {
return U.compareAndSwapLong(array, offset, expect, update);
public final boolean compareAndSet(int i, long expectedValue, long newValue) {
return AA.compareAndSet(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(int i, long expect, long update) {
return compareAndSet(i, expect, update);
public final boolean weakCompareAndSet(int i, long expectedValue, long newValue) {
return AA.weakCompareAndSet(array, i, expectedValue, newValue);
}
/**
* Atomically increments by one the element at index {@code i}.
* Atomically increments the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(i, 1)}.
*
* @param i the index
* @return the previous value
*/
public final long getAndIncrement(int i) {
return getAndAdd(i, 1);
return (long)AA.getAndAdd(array, i, 1L);
}
/**
* Atomically decrements by one the element at index {@code i}.
* Atomically decrements the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* <p>Equivalent to {@code getAndAdd(i, -1)}.
*
* @param i the index
* @return the previous value
*/
public final long getAndDecrement(int i) {
return getAndAdd(i, -1);
return (long)AA.getAndAdd(array, i, -1L);
}
/**
* Atomically adds the given value to the element at index {@code i}.
* Atomically adds the given value to the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAndAdd}.
*
* @param i the index
* @param delta the value to add
* @return the previous value
*/
public final long getAndAdd(int i, long delta) {
return U.getAndAddLong(array, checkedByteOffset(i), delta);
return (long)AA.getAndAdd(array, i, delta);
}
/**
* Atomically increments by one the element at index {@code i}.
* Atomically increments the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(i, 1)}.
*
* @param i the index
* @return the updated value
*/
public final long incrementAndGet(int i) {
return getAndAdd(i, 1) + 1;
return (long)AA.addAndGet(array, i, 1L);
}
/**
* Atomically decrements by one the element at index {@code i}.
* Atomically decrements the value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* <p>Equivalent to {@code addAndGet(i, -1)}.
*
* @param i the index
* @return the updated value
*/
public final long decrementAndGet(int i) {
return getAndAdd(i, -1) - 1;
return (long)AA.addAndGet(array, i, -1L);
}
/**
* Atomically adds the given value to the element at index {@code i}.
* Atomically adds the given value to the element at index {@code i},
* with memory effects as specified by {@link VarHandle#addAndGet}.
*
* @param i the index
* @param delta the value to add
* @return the updated value
*/
public long addAndGet(int i, long delta) {
return getAndAdd(i, delta) + delta;
return (long)AA.addAndGet(array, i, delta);
}
/**
@ -259,13 +248,14 @@ public class AtomicLongArray implements java.io.Serializable {
* @since 1.8
*/
public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
long prev, next;
do {
prev = getRaw(offset);
next = updateFunction.applyAsLong(prev);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
long prev = get(i), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsLong(prev);
if (weakCompareAndSetVolatile(i, prev, next))
return prev;
haveNext = (prev == (prev = get(i)));
}
}
/**
@ -280,23 +270,25 @@ public class AtomicLongArray implements java.io.Serializable {
* @since 1.8
*/
public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
long offset = checkedByteOffset(i);
long prev, next;
do {
prev = getRaw(offset);
next = updateFunction.applyAsLong(prev);
} while (!compareAndSetRaw(offset, prev, next));
return next;
long prev = get(i), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsLong(prev);
if (weakCompareAndSetVolatile(i, prev, next))
return next;
haveNext = (prev == (prev = get(i)));
}
}
/**
* Atomically updates the element at index {@code i} with the
* results of applying the given function to the current and
* given values, returning the previous value. The function should
* be side-effect-free, since it may be re-applied when attempted
* results of applying the given function to the current and given
* values, returning the previous value. The function should be
* side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
* applied with the current value at index {@code i} as its first
* argument, and the given update as the second argument.
* applied with the current value of the element at index {@code i}
* as its first argument, and the given update as the second
* argument.
*
* @param i the index
* @param x the update value
@ -306,23 +298,25 @@ public class AtomicLongArray implements java.io.Serializable {
*/
public final long getAndAccumulate(int i, long x,
LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
long prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.applyAsLong(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
long prev = get(i), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsLong(prev, x);
if (weakCompareAndSetVolatile(i, prev, next))
return prev;
haveNext = (prev == (prev = get(i)));
}
}
/**
* Atomically updates the element at index {@code i} with the
* results of applying the given function to the current and
* given values, returning the updated value. The function should
* be side-effect-free, since it may be re-applied when attempted
* results of applying the given function to the current and given
* values, returning the updated value. The function should be
* side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
* applied with the current value at index {@code i} as its first
* argument, and the given update as the second argument.
* applied with the current value of the element at index {@code i}
* as its first argument, and the given update as the second
* argument.
*
* @param i the index
* @param x the update value
@ -332,13 +326,14 @@ public class AtomicLongArray implements java.io.Serializable {
*/
public final long accumulateAndGet(int i, long x,
LongBinaryOperator accumulatorFunction) {
long offset = checkedByteOffset(i);
long prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.applyAsLong(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return next;
long prev = get(i), next = 0L;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsLong(prev, x);
if (weakCompareAndSetVolatile(i, prev, next))
return next;
haveNext = (prev == (prev = get(i)));
}
}
/**
@ -353,11 +348,189 @@ public class AtomicLongArray implements java.io.Serializable {
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
b.append(get(i));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
}
// jdk9
/**
* Returns the current value of the element at index {@code i},
* with memory semantics of reading as if the variable was declared
* non-{@code volatile}.
*
* @param i the index
* @return the value
* @since 9
*/
public final long getPlain(int i) {
return (long)AA.get(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory semantics of setting as if the variable was
* declared non-{@code volatile} and non-{@code final}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setPlain(int i, long newValue) {
AA.set(array, i, newValue);
}
/**
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @param i the index
* @return the value
* @since 9
*/
public final long getOpaque(int i) {
return (long)AA.getOpaque(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setOpaque(int i, long newValue) {
AA.setOpaque(array, i, newValue);
}
/**
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @param i the index
* @return the value
* @since 9
*/
public final long getAcquire(int i) {
return (long)AA.getAcquire(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setRelease(int i, long newValue) {
AA.setRelease(array, i, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final long compareAndExchange(int i, long expectedValue, long newValue) {
return (long)AA.compareAndExchange(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final long compareAndExchangeAcquire(int i, long expectedValue, long newValue) {
return (long)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final long compareAndExchangeRelease(int i, long expectedValue, long newValue) {
return (long)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(int i, long expectedValue, long newValue) {
return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(int i, long expectedValue, long newValue) {
return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(int i, long expectedValue, long newValue) {
return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
}
}

View File

@ -42,6 +42,7 @@ import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.function.LongBinaryOperator;
import java.util.function.LongUnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@ -153,8 +154,8 @@ public abstract class AtomicLongFieldUpdater<T> {
public abstract void lazySet(T obj, long newValue);
/**
* Gets the current value held in the field of the given object managed
* by this updater.
* Returns the current value held in the field of the given object
* managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@ -366,7 +367,7 @@ public abstract class AtomicLongFieldUpdater<T> {
}
private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else
@ -497,7 +498,7 @@ public abstract class AtomicLongFieldUpdater<T> {
}
private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else

View File

@ -35,6 +35,9 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* An {@code AtomicMarkableReference} maintains an object reference
* along with a mark bit, that can be updated atomically.
@ -188,20 +191,19 @@ public class AtomicMarkableReference<V> {
casPair(current, Pair.of(expectedReference, newMark)));
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long PAIR;
// VarHandle mechanics
private static final VarHandle PAIR;
static {
try {
PAIR = U.objectFieldOffset
(AtomicMarkableReference.class.getDeclaredField("pair"));
MethodHandles.Lookup l = MethodHandles.lookup();
PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
Pair.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return U.compareAndSwapObject(this, PAIR, cmp, val);
return PAIR.compareAndSet(this, cmp, val);
}
}

View File

@ -35,33 +35,32 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
/**
* An object reference that may be updated atomically. See the {@link
* java.util.concurrent.atomic} package specification for description
* of the properties of atomic variables.
* An object reference that may be updated atomically. See the {@link
* VarHandle} specification for descriptions of the properties of
* atomic accesses.
* @since 1.5
* @author Doug Lea
* @param <V> The type of object referred to by this reference
*/
public class AtomicReference<V> implements java.io.Serializable {
private static final long serialVersionUID = -1848883965231344442L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE;
private static final VarHandle VALUE;
static {
try {
VALUE = U.objectFieldOffset
(AtomicReference.class.getDeclaredField("value"));
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
private volatile V value;
private volatile Object value;
/**
* Creates a new AtomicReference with the given initial value.
@ -79,16 +78,19 @@ public class AtomicReference<V> implements java.io.Serializable {
}
/**
* Gets the current value.
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @return the current value
*/
@SuppressWarnings("unchecked")
public final V get() {
return value;
return (V)value;
}
/**
* Sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param newValue the new value
*/
@ -97,52 +99,53 @@ public class AtomicReference<V> implements java.io.Serializable {
}
/**
* Eventually sets to the given value.
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(V newValue) {
U.putObjectRelease(this, VALUE, newValue);
VALUE.setRelease(this, newValue);
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* @param expect the expected value
* @param update the new value
* Atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(V expect, V update) {
return U.compareAndSwapObject(this, VALUE, expect, update);
public final boolean compareAndSet(V expectedValue, V newValue) {
return VALUE.compareAndSet(this, expectedValue, newValue);
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
*
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(V expect, V update) {
return U.compareAndSwapObject(this, VALUE, expect, update);
public final boolean weakCompareAndSet(V expectedValue, V newValue) {
return VALUE.weakCompareAndSet(this, expectedValue, newValue);
}
/**
* Atomically sets to the given value and returns the old value.
* Atomically sets the value to {@code newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param newValue the new value
* @return the previous value
*/
@SuppressWarnings("unchecked")
public final V getAndSet(V newValue) {
return (V)U.getAndSetObject(this, VALUE, newValue);
return (V)VALUE.getAndSet(this, newValue);
}
/**
@ -156,12 +159,14 @@ public class AtomicReference<V> implements java.io.Serializable {
* @since 1.8
*/
public final V getAndUpdate(UnaryOperator<V> updateFunction) {
V prev, next;
do {
prev = get();
next = updateFunction.apply(prev);
} while (!compareAndSet(prev, next));
return prev;
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.apply(prev);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
/**
@ -175,12 +180,14 @@ public class AtomicReference<V> implements java.io.Serializable {
* @since 1.8
*/
public final V updateAndGet(UnaryOperator<V> updateFunction) {
V prev, next;
do {
prev = get();
next = updateFunction.apply(prev);
} while (!compareAndSet(prev, next));
return next;
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.apply(prev);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
/**
@ -199,12 +206,14 @@ public class AtomicReference<V> implements java.io.Serializable {
*/
public final V getAndAccumulate(V x,
BinaryOperator<V> accumulatorFunction) {
V prev, next;
do {
prev = get();
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSet(prev, next));
return prev;
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.apply(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
/**
@ -223,12 +232,14 @@ public class AtomicReference<V> implements java.io.Serializable {
*/
public final V accumulateAndGet(V x,
BinaryOperator<V> accumulatorFunction) {
V prev, next;
do {
prev = get();
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSet(prev, next));
return next;
V prev = get(), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.apply(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
/**
@ -239,4 +250,166 @@ public class AtomicReference<V> implements java.io.Serializable {
return String.valueOf(get());
}
// jdk9
/**
* Returns the current value, with memory semantics of reading as
* if the variable was declared non-{@code volatile}.
*
* @return the value
* @since 9
*/
public final V getPlain() {
return (V)VALUE.get(this);
}
/**
* Sets the value to {@code newValue}, with memory semantics
* of setting as if the variable was declared non-{@code volatile}
* and non-{@code final}.
*
* @param newValue the new value
* @since 9
*/
public final void setPlain(V newValue) {
VALUE.set(this, newValue);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @return the value
* @since 9
*/
public final V getOpaque() {
return (V)VALUE.getOpaque(this);
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param newValue the new value
* @since 9
*/
public final void setOpaque(V newValue) {
VALUE.setOpaque(this, newValue);
}
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @return the value
* @since 9
*/
public final V getAcquire() {
return (V)VALUE.getAcquire(this);
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param newValue the new value
* @since 9
*/
public final void setRelease(V newValue) {
VALUE.setRelease(this, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final V compareAndExchange(V expectedValue, V newValue) {
return (V)VALUE.compareAndExchange(this, expectedValue, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final V compareAndExchangeAcquire(V expectedValue, V newValue) {
return (V)VALUE.compareAndExchangeAcquire(this, expectedValue, newValue);
}
/**
* Atomically sets the value to {@code newValue} if the current value,
* referred to as the <em>witness value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final V compareAndExchangeRelease(V expectedValue, V newValue) {
return (V)VALUE.compareAndExchangeRelease(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(V expectedValue, V newValue) {
return VALUE.weakCompareAndSetVolatile(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(V expectedValue, V newValue) {
return VALUE.weakCompareAndSetAcquire(this, expectedValue, newValue);
}
/**
* Possibly atomically sets the value to {@code newValue}
* if the current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(V expectedValue, V newValue) {
return VALUE.weakCompareAndSetRelease(this, expectedValue, newValue);
}
}

View File

@ -35,54 +35,28 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
/**
* An array of object references in which elements may be updated
* atomically. See the {@link java.util.concurrent.atomic} package
* specification for description of the properties of atomic
* variables.
* atomically. See the {@link VarHandle} specification for
* descriptions of the properties of atomic accesses.
* @since 1.5
* @author Doug Lea
* @param <E> The base class of elements held in this array
*/
public class AtomicReferenceArray<E> implements java.io.Serializable {
private static final long serialVersionUID = -6209656149925076980L;
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long ARRAY;
private static final int ABASE;
private static final int ASHIFT;
private static final VarHandle AA
= MethodHandles.arrayElementVarHandle(Object[].class);
private final Object[] array; // must have exact type Object[]
static {
try {
ARRAY = U.objectFieldOffset
(AtomicReferenceArray.class.getDeclaredField("array"));
ABASE = U.arrayBaseOffset(Object[].class);
int scale = U.arrayIndexScale(Object[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("array index scale not a power of two");
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << ASHIFT) + ABASE;
}
/**
* Creates a new AtomicReferenceArray of the given length, with all
* elements initially null.
@ -115,44 +89,44 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
}
/**
* Gets the current value at position {@code i}.
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getVolatile}.
*
* @param i the index
* @return the current value
*/
public final E get(int i) {
return getRaw(checkedByteOffset(i));
}
@SuppressWarnings("unchecked")
private E getRaw(long offset) {
return (E) U.getObjectVolatile(array, offset);
public final E get(int i) {
return (E)AA.getVolatile(array, i);
}
/**
* Sets the element at position {@code i} to the given value.
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*
* @param i the index
* @param newValue the new value
*/
public final void set(int i, E newValue) {
U.putObjectVolatile(array, checkedByteOffset(i), newValue);
AA.setVolatile(array, i, newValue);
}
/**
* Eventually sets the element at position {@code i} to the given value.
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 1.6
*/
public final void lazySet(int i, E newValue) {
U.putObjectRelease(array, checkedByteOffset(i), newValue);
AA.setRelease(array, i, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* value and returns the old value.
* Atomically sets the element at index {@code i} to {@code
* newValue} and returns the old value,
* with memory effects as specified by {@link VarHandle#getAndSet}.
*
* @param i the index
* @param newValue the new value
@ -160,42 +134,36 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
*/
@SuppressWarnings("unchecked")
public final E getAndSet(int i, E newValue) {
return (E)U.getAndSetObject(array, checkedByteOffset(i), newValue);
return (E)AA.getAndSet(array, i, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#compareAndSet}.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int i, E expect, E update) {
return compareAndSetRaw(checkedByteOffset(i), expect, update);
}
private boolean compareAndSetRaw(long offset, E expect, E update) {
return U.compareAndSwapObject(array, offset, expect, update);
public final boolean compareAndSet(int i, E expectedValue, E newValue) {
return AA.compareAndSet(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value.
*
* <p><a href="package-summary.html#weakCompareAndSet">May fail
* spuriously and does not provide ordering guarantees</a>, so is
* only rarely an appropriate alternative to {@code compareAndSet}.
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by {@link VarHandle#weakCompareAndSet}.
*
* @param i the index
* @param expect the expected value
* @param update the new value
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
*/
public final boolean weakCompareAndSet(int i, E expect, E update) {
return compareAndSet(i, expect, update);
public final boolean weakCompareAndSet(int i, E expectedValue, E newValue) {
return AA.weakCompareAndSet(array, i, expectedValue, newValue);
}
/**
@ -210,13 +178,14 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @since 1.8
*/
public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
long offset = checkedByteOffset(i);
E prev, next;
do {
prev = getRaw(offset);
next = updateFunction.apply(prev);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
E prev = get(i), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.apply(prev);
if (weakCompareAndSetVolatile(i, prev, next))
return prev;
haveNext = (prev == (prev = get(i)));
}
}
/**
@ -231,23 +200,25 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @since 1.8
*/
public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
long offset = checkedByteOffset(i);
E prev, next;
do {
prev = getRaw(offset);
next = updateFunction.apply(prev);
} while (!compareAndSetRaw(offset, prev, next));
return next;
E prev = get(i), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.apply(prev);
if (weakCompareAndSetVolatile(i, prev, next))
return next;
haveNext = (prev == (prev = get(i)));
}
}
/**
* Atomically updates the element at index {@code i} with the
* results of applying the given function to the current and
* given values, returning the previous value. The function should
* be side-effect-free, since it may be re-applied when attempted
* results of applying the given function to the current and given
* values, returning the previous value. The function should be
* side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
* applied with the current value at index {@code i} as its first
* argument, and the given update as the second argument.
* applied with the current value of the element at index {@code i}
* as its first argument, and the given update as the second
* argument.
*
* @param i the index
* @param x the update value
@ -257,23 +228,25 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
*/
public final E getAndAccumulate(int i, E x,
BinaryOperator<E> accumulatorFunction) {
long offset = checkedByteOffset(i);
E prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return prev;
E prev = get(i), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.apply(prev, x);
if (weakCompareAndSetVolatile(i, prev, next))
return prev;
haveNext = (prev == (prev = get(i)));
}
}
/**
* Atomically updates the element at index {@code i} with the
* results of applying the given function to the current and
* given values, returning the updated value. The function should
* be side-effect-free, since it may be re-applied when attempted
* results of applying the given function to the current and given
* values, returning the updated value. The function should be
* side-effect-free, since it may be re-applied when attempted
* updates fail due to contention among threads. The function is
* applied with the current value at index {@code i} as its first
* argument, and the given update as the second argument.
* applied with the current value of the element at index {@code i}
* as its first argument, and the given update as the second
* argument.
*
* @param i the index
* @param x the update value
@ -283,13 +256,14 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
*/
public final E accumulateAndGet(int i, E x,
BinaryOperator<E> accumulatorFunction) {
long offset = checkedByteOffset(i);
E prev, next;
do {
prev = getRaw(offset);
next = accumulatorFunction.apply(prev, x);
} while (!compareAndSetRaw(offset, prev, next));
return next;
E prev = get(i), next = null;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.apply(prev, x);
if (weakCompareAndSetVolatile(i, prev, next))
return next;
haveNext = (prev == (prev = get(i)));
}
}
/**
@ -304,7 +278,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
b.append(get(i));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
@ -326,7 +300,199 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
throw new java.io.InvalidObjectException("Not array type");
if (a.getClass() != Object[].class)
a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
U.putObjectVolatile(this, ARRAY, a);
Field arrayField = java.security.AccessController.doPrivileged(
(java.security.PrivilegedAction<Field>) () -> {
try {
Field f = AtomicReferenceArray.class
.getDeclaredField("array");
f.setAccessible(true);
return f;
} catch (ReflectiveOperationException e) {
throw new Error(e);
}});
try {
arrayField.set(this, a);
} catch (IllegalAccessException e) {
throw new Error(e);
}
}
// jdk9
/**
* Returns the current value of the element at index {@code i},
* with memory semantics of reading as if the variable was declared
* non-{@code volatile}.
*
* @param i the index
* @return the value
* @since 9
*/
public final E getPlain(int i) {
return (E)AA.get(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory semantics of setting as if the variable was
* declared non-{@code volatile} and non-{@code final}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setPlain(int i, E newValue) {
AA.set(array, i, newValue);
}
/**
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getOpaque}.
*
* @param i the index
* @return the value
* @since 9
*/
public final E getOpaque(int i) {
return (E)AA.getOpaque(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setOpaque}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setOpaque(int i, E newValue) {
AA.setOpaque(array, i, newValue);
}
/**
* Returns the current value of the element at index {@code i},
* with memory effects as specified by {@link VarHandle#getAcquire}.
*
* @param i the index
* @return the value
* @since 9
*/
public final E getAcquire(int i) {
return (E)AA.getAcquire(array, i);
}
/**
* Sets the element at index {@code i} to {@code newValue},
* with memory effects as specified by {@link VarHandle#setRelease}.
*
* @param i the index
* @param newValue the new value
* @since 9
*/
public final void setRelease(int i, E newValue) {
AA.setRelease(array, i, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchange}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final E compareAndExchange(int i, E expectedValue, E newValue) {
return (E)AA.compareAndExchange(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeAcquire}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final E compareAndExchangeAcquire(int i, E expectedValue, E newValue) {
return (E)AA.compareAndExchangeAcquire(array, i, expectedValue, newValue);
}
/**
* Atomically sets the element at index {@code i} to {@code newValue}
* if the element's current value, referred to as the <em>witness
* value</em>, {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#compareAndExchangeRelease}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return the witness value, which will be the same as the
* expected value if successful
* @since 9
*/
public final E compareAndExchangeRelease(int i, E expectedValue, E newValue) {
return (E)AA.compareAndExchangeRelease(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetVolatile}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetVolatile(int i, E expectedValue, E newValue) {
return AA.weakCompareAndSetVolatile(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetAcquire}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetAcquire(int i, E expectedValue, E newValue) {
return AA.weakCompareAndSetAcquire(array, i, expectedValue, newValue);
}
/**
* Possibly atomically sets the element at index {@code i} to
* {@code newValue} if the element's current value {@code == expectedValue},
* with memory effects as specified by
* {@link VarHandle#weakCompareAndSetRelease}.
*
* @param i the index
* @param expectedValue the expected value
* @param newValue the new value
* @return {@code true} if successful
* @since 9
*/
public final boolean weakCompareAndSetRelease(int i, E expectedValue, E newValue) {
return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue);
}
}

View File

@ -42,6 +42,7 @@ import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.function.BinaryOperator;
import java.util.function.UnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
@ -168,8 +169,8 @@ public abstract class AtomicReferenceFieldUpdater<T,V> {
public abstract void lazySet(T obj, V newValue);
/**
* Gets the current value held in the field of the given object managed
* by this updater.
* Returns the current value held in the field of the given object
* managed by this updater.
*
* @param obj An object whose field to get
* @return the current value
@ -284,7 +285,7 @@ public abstract class AtomicReferenceFieldUpdater<T,V> {
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;
/**
* if field is protected, the subclass constructing updater, else

View File

@ -35,6 +35,9 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
/**
* An {@code AtomicStampedReference} maintains an object reference
* along with an integer "stamp", that can be updated atomically.
@ -188,20 +191,19 @@ public class AtomicStampedReference<V> {
casPair(current, Pair.of(expectedReference, newStamp)));
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long PAIR;
// VarHandle mechanics
private static final VarHandle PAIR;
static {
try {
PAIR = U.objectFieldOffset
(AtomicStampedReference.class.getDeclaredField("pair"));
MethodHandles.Lookup l = MethodHandles.lookup();
PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
Pair.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return U.compareAndSwapObject(this, PAIR, cmp, val);
return PAIR.compareAndSet(this, cmp, val);
}
}

View File

@ -68,7 +68,7 @@ import java.util.function.LongBinaryOperator;
* <p>Class {@link LongAdder} provides analogs of the functionality of
* this class for the common special case of maintaining counts and
* sums. The call {@code new LongAdder()} is equivalent to {@code new
* LongAccumulator((x, y) -> x + y, 0L}.
* LongAccumulator((x, y) -> x + y, 0L)}.
*
* <p>This class extends {@link Number}, but does <em>not</em> define
* methods such as {@code equals}, {@code hashCode} and {@code

View File

@ -35,10 +35,13 @@
package java.util.concurrent.atomic;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.DoubleBinaryOperator;
import java.util.function.LongBinaryOperator;
import jdk.internal.misc.Unsafe;
/**
* A package-local class holding common representation and mechanics
@ -123,22 +126,21 @@ abstract class Striped64 extends Number {
volatile long value;
Cell(long x) { value = x; }
final boolean cas(long cmp, long val) {
return U.compareAndSwapLong(this, VALUE, cmp, val);
return VALUE.compareAndSet(this, cmp, val);
}
final void reset() {
U.putLongVolatile(this, VALUE, 0L);
VALUE.setVolatile(this, 0L);
}
final void reset(long identity) {
U.putLongVolatile(this, VALUE, identity);
VALUE.setVolatile(this, identity);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long VALUE;
// VarHandle mechanics
private static final VarHandle VALUE;
static {
try {
VALUE = U.objectFieldOffset
(Cell.class.getDeclaredField("value"));
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(Cell.class, "value", long.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -174,14 +176,14 @@ abstract class Striped64 extends Number {
* CASes the base field.
*/
final boolean casBase(long cmp, long val) {
return U.compareAndSwapLong(this, BASE, cmp, val);
return BASE.compareAndSet(this, cmp, val);
}
/**
* CASes the cellsBusy field from 0 to 1 to acquire lock.
*/
final boolean casCellsBusy() {
return U.compareAndSwapInt(this, CELLSBUSY, 0, 1);
return CELLSBUSY.compareAndSet(this, 0, 1);
}
/**
@ -371,18 +373,16 @@ abstract class Striped64 extends Number {
}
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long BASE;
private static final long CELLSBUSY;
// Unsafe and VarHandle mechanics
private static final Unsafe U = Unsafe.getUnsafe();
private static final VarHandle BASE;
private static final VarHandle CELLSBUSY;
private static final long PROBE;
static {
try {
BASE = U.objectFieldOffset
(Striped64.class.getDeclaredField("base"));
CELLSBUSY = U.objectFieldOffset
(Striped64.class.getDeclaredField("cellsBusy"));
MethodHandles.Lookup l = MethodHandles.lookup();
BASE = l.findVarHandle(Striped64.class, "base", long.class);
CELLSBUSY = l.findVarHandle(Striped64.class, "cellsBusy", int.class);
PROBE = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomProbe"));
} catch (ReflectiveOperationException e) {

View File

@ -35,26 +35,10 @@
/**
* A small toolkit of classes that support lock-free thread-safe
* programming on single variables. In essence, the classes in this
* package extend the notion of {@code volatile} values, fields, and
* array elements to those that also provide an atomic conditional update
* operation of the form:
*
* <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
*
* <p>This method (which varies in argument types across different
* classes) atomically sets a variable to the {@code updateValue} if it
* currently holds the {@code expectedValue}, reporting {@code true} on
* success. The classes in this package also contain methods to get and
* unconditionally set values, as well as a weaker conditional atomic
* update operation {@code weakCompareAndSet} described below.
*
* <p>The specifications of these methods enable implementations to
* employ efficient machine-level atomic instructions that are available
* on contemporary processors. However on some platforms, support may
* entail some form of internal locking. Thus the methods are not
* strictly guaranteed to be non-blocking --
* a thread may block transiently before performing the operation.
* programming on single variables. Instances of Atomic classes
* maintain values that are accessed and updated using methods
* otherwise available for fields using associated atomic {@link
* java.lang.invoke.VarHandle} operations.
*
* <p>Instances of classes
* {@link java.util.concurrent.atomic.AtomicBoolean},
@ -92,45 +76,26 @@
* return prev; // return next; for transformAndGet
* }}</pre>
*
* <p>The memory effects for accesses and updates of atomics generally
* follow the rules for volatiles, as stated in
* <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
* Chapter 17 of
* <cite>The Java&trade; Language Specification</cite></a>:
* <p>These classes are not general purpose replacements for {@code
* java.lang.Integer} and related classes. They do <em>not</em>
* define methods such as {@code equals}, {@code hashCode} and {@code
* compareTo}. Because atomic variables are expected to be mutated,
* they are poor choices for hash table keys.
*
* <ul>
*
* <li>{@code get} has the memory effects of reading a
* {@code volatile} variable.
*
* <li>{@code set} has the memory effects of writing (assigning) a
* {@code volatile} variable.
*
* <li>{@code lazySet} has the memory effects of writing (assigning)
* a {@code volatile} variable except that it permits reorderings with
* subsequent (but not previous) memory actions that do not themselves
* impose reordering constraints with ordinary non-{@code volatile}
* writes. Among other usage contexts, {@code lazySet} may apply when
* nulling out, for the sake of garbage collection, a reference that is
* never accessed again.
*
* <li>{@code weakCompareAndSet} atomically reads and conditionally
* writes a variable but does <em>not</em>
* create any happens-before orderings, so provides no guarantees
* with respect to previous or subsequent reads and writes of any
* variables other than the target of the {@code weakCompareAndSet}.
*
* <li>{@code compareAndSet}
* and all other read-and-update operations such as {@code getAndIncrement}
* have the memory effects of both reading and
* writing {@code volatile} variables.
* </ul>
*
* <p>In addition to classes representing single values, this package
* contains <em>Updater</em> classes that can be used to obtain
* {@code compareAndSet} operations on any selected {@code volatile}
* field of any selected class.
* <p>The
* {@link java.util.concurrent.atomic.AtomicIntegerArray},
* {@link java.util.concurrent.atomic.AtomicLongArray}, and
* {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
* further extend atomic operation support to arrays of these types.
* These classes are also notable in providing {@code volatile} access
* semantics for their array elements.
*
* <p>In addition to classes representing single values and arrays,
* this package contains <em>Updater</em> classes that can be used to
* obtain {@code compareAndSet} and related operations on any selected
* {@code volatile} field of any selected class. These classes
* predate the introduction of {@link
* java.lang.invoke.VarHandle}, and are of more limited use.
* {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
* {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
* {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
@ -143,38 +108,6 @@
* reflection-based setup, less convenient usage, and weaker
* guarantees.
*
* <p>The
* {@link java.util.concurrent.atomic.AtomicIntegerArray},
* {@link java.util.concurrent.atomic.AtomicLongArray}, and
* {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
* further extend atomic operation support to arrays of these types.
* These classes are also notable in providing {@code volatile} access
* semantics for their array elements, which is not supported for
* ordinary arrays.
*
* <p id="weakCompareAndSet">The atomic classes also support method
* {@code weakCompareAndSet}, which has limited applicability. On some
* platforms, the weak version may be more efficient than {@code
* compareAndSet} in the normal case, but differs in that any given
* invocation of the {@code weakCompareAndSet} method may return {@code
* false} <em>spuriously</em> (that is, for no apparent reason). A
* {@code false} return means only that the operation may be retried if
* desired, relying on the guarantee that repeated invocation when the
* variable holds {@code expectedValue} and no other thread is also
* attempting to set the variable will eventually succeed. (Such
* spurious failures may for example be due to memory contention effects
* that are unrelated to whether the expected and current values are
* equal.) Additionally {@code weakCompareAndSet} does not provide
* ordering guarantees that are usually needed for synchronization
* control. However, the method may be useful for updating counters and
* statistics when such updates are unrelated to the other
* happens-before orderings of a program. When a thread sees an update
* to an atomic variable caused by a {@code weakCompareAndSet}, it does
* not necessarily see updates to any <em>other</em> variables that
* occurred before the {@code weakCompareAndSet}. This may be
* acceptable when, for example, updating performance statistics, but
* rarely otherwise.
*
* <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
* class associates a single boolean with a reference. For example, this
* bit might be used inside a data structure to mean that the object
@ -185,29 +118,6 @@
* used for example, to represent version numbers corresponding to
* series of updates.
*
* <p>Atomic classes are designed primarily as building blocks for
* implementing non-blocking data structures and related infrastructure
* classes. The {@code compareAndSet} method is not a general
* replacement for locking. It applies only when critical updates for an
* object are confined to a <em>single</em> variable.
*
* <p>Atomic classes are not general purpose replacements for
* {@code java.lang.Integer} and related classes. They do <em>not</em>
* define methods such as {@code equals}, {@code hashCode} and
* {@code compareTo}. (Because atomic variables are expected to be
* mutated, they are poor choices for hash table keys.) Additionally,
* classes are provided only for those types that are commonly useful in
* intended applications. For example, there is no atomic class for
* representing {@code byte}. In those infrequent cases where you would
* like to do so, you can use an {@code AtomicInteger} to hold
* {@code byte} values, and cast appropriately.
*
* You can also hold floats using
* {@link java.lang.Float#floatToRawIntBits} and
* {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
* {@link java.lang.Double#doubleToRawLongBits} and
* {@link java.lang.Double#longBitsToDouble} conversions.
*
* @since 1.5
*/
package java.util.concurrent.atomic;

View File

@ -35,6 +35,8 @@
package java.util.concurrent.locks;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
@ -113,7 +115,7 @@ public abstract class AbstractQueuedLongSynchronizer
protected final void setState(long newState) {
// Use putLongVolatile instead of ordinary volatile store when
// using compareAndSwapLong, for sake of some 32bit systems.
U.putLongVolatile(this, STATE, newState);
STATE.setVolatile(this, newState);
}
/**
@ -128,7 +130,7 @@ public abstract class AbstractQueuedLongSynchronizer
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(long expect, long update) {
return U.compareAndSwapLong(this, STATE, expect, update);
return STATE.compareAndSet(this, expect, update);
}
// Queuing utilities
@ -149,7 +151,7 @@ public abstract class AbstractQueuedLongSynchronizer
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
U.putObject(node, Node.PREV, oldTail);
node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return oldTail;
@ -172,7 +174,7 @@ public abstract class AbstractQueuedLongSynchronizer
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
U.putObject(node, Node.PREV, oldTail);
node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
@ -1810,28 +1812,17 @@ public abstract class AbstractQueuedLongSynchronizer
}
}
/**
* Setup to support compareAndSet. We need to natively implement
* this here: For the sake of permitting future enhancements, we
* cannot explicitly subclass AtomicLong, which would be
* efficient and useful otherwise. So, as the lesser of evils, we
* natively implement using hotspot intrinsics API. And while we
* are at it, we do the same for other CASable fields (which could
* otherwise be done with atomic field updaters).
*/
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATE;
private static final long HEAD;
private static final long TAIL;
// VarHandle mechanics
private static final VarHandle STATE;
private static final VarHandle HEAD;
private static final VarHandle TAIL;
static {
try {
STATE = U.objectFieldOffset
(AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
HEAD = U.objectFieldOffset
(AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
TAIL = U.objectFieldOffset
(AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "state", long.class);
HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -1846,7 +1837,7 @@ public abstract class AbstractQueuedLongSynchronizer
*/
private final void initializeSyncQueue() {
Node h;
if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
if (HEAD.compareAndSet(this, null, (h = new Node())))
tail = h;
}
@ -1854,6 +1845,6 @@ public abstract class AbstractQueuedLongSynchronizer
* CASes tail field.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return U.compareAndSwapObject(this, TAIL, expect, update);
return TAIL.compareAndSet(this, expect, update);
}
}

View File

@ -35,11 +35,12 @@
package java.util.concurrent.locks;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* Provides a framework for implementing blocking locks and related
@ -506,40 +507,41 @@ public abstract class AbstractQueuedSynchronizer
/** Constructor used by addWaiter. */
Node(Node nextWaiter) {
this.nextWaiter = nextWaiter;
U.putObject(this, THREAD, Thread.currentThread());
THREAD.set(this, Thread.currentThread());
}
/** Constructor used by addConditionWaiter. */
Node(int waitStatus) {
U.putInt(this, WAITSTATUS, waitStatus);
U.putObject(this, THREAD, Thread.currentThread());
WAITSTATUS.set(this, waitStatus);
THREAD.set(this, Thread.currentThread());
}
/** CASes waitStatus field. */
final boolean compareAndSetWaitStatus(int expect, int update) {
return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
return WAITSTATUS.compareAndSet(this, expect, update);
}
/** CASes next field. */
final boolean compareAndSetNext(Node expect, Node update) {
return U.compareAndSwapObject(this, NEXT, expect, update);
return NEXT.compareAndSet(this, expect, update);
}
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long NEXT;
static final long PREV;
private static final long THREAD;
private static final long WAITSTATUS;
final void setPrevRelaxed(Node p) {
PREV.set(this, p);
}
// VarHandle mechanics
private static final VarHandle NEXT;
private static final VarHandle PREV;
private static final VarHandle THREAD;
private static final VarHandle WAITSTATUS;
static {
try {
NEXT = U.objectFieldOffset
(Node.class.getDeclaredField("next"));
PREV = U.objectFieldOffset
(Node.class.getDeclaredField("prev"));
THREAD = U.objectFieldOffset
(Node.class.getDeclaredField("thread"));
WAITSTATUS = U.objectFieldOffset
(Node.class.getDeclaredField("waitStatus"));
MethodHandles.Lookup l = MethodHandles.lookup();
NEXT = l.findVarHandle(Node.class, "next", Node.class);
PREV = l.findVarHandle(Node.class, "prev", Node.class);
THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -595,7 +597,7 @@ public abstract class AbstractQueuedSynchronizer
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
return U.compareAndSwapInt(this, STATE, expect, update);
return STATE.compareAndSet(this, expect, update);
}
// Queuing utilities
@ -616,7 +618,7 @@ public abstract class AbstractQueuedSynchronizer
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
U.putObject(node, Node.PREV, oldTail);
node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return oldTail;
@ -639,7 +641,7 @@ public abstract class AbstractQueuedSynchronizer
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
U.putObject(node, Node.PREV, oldTail);
node.setPrevRelaxed(oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
@ -887,7 +889,6 @@ public abstract class AbstractQueuedSynchronizer
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
@ReservedStackAccess
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
@ -1220,7 +1221,6 @@ public abstract class AbstractQueuedSynchronizer
* {@link #tryAcquire} but is otherwise uninterpreted and
* can represent anything you like.
*/
@ReservedStackAccess
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
@ -1284,7 +1284,6 @@ public abstract class AbstractQueuedSynchronizer
* can represent anything you like.
* @return the value returned from {@link #tryRelease}
*/
@ReservedStackAccess
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
@ -1365,7 +1364,6 @@ public abstract class AbstractQueuedSynchronizer
* and can represent anything you like.
* @return the value returned from {@link #tryReleaseShared}
*/
@ReservedStackAccess
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
@ -2279,28 +2277,17 @@ public abstract class AbstractQueuedSynchronizer
}
}
/**
* Setup to support compareAndSet. We need to natively implement
* this here: For the sake of permitting future enhancements, we
* cannot explicitly subclass AtomicInteger, which would be
* efficient and useful otherwise. So, as the lesser of evils, we
* natively implement using hotspot intrinsics API. And while we
* are at it, we do the same for other CASable fields (which could
* otherwise be done with atomic field updaters).
*/
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATE;
private static final long HEAD;
private static final long TAIL;
// VarHandle mechanics
private static final VarHandle STATE;
private static final VarHandle HEAD;
private static final VarHandle TAIL;
static {
try {
STATE = U.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
HEAD = U.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
TAIL = U.objectFieldOffset
(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
@ -2315,7 +2302,7 @@ public abstract class AbstractQueuedSynchronizer
*/
private final void initializeSyncQueue() {
Node h;
if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
if (HEAD.compareAndSet(this, null, (h = new Node())))
tail = h;
}
@ -2323,6 +2310,6 @@ public abstract class AbstractQueuedSynchronizer
* CASes tail field.
*/
private final boolean compareAndSetTail(Node expect, Node update) {
return U.compareAndSwapObject(this, TAIL, expect, update);
return TAIL.compareAndSet(this, expect, update);
}
}

View File

@ -396,7 +396,6 @@ public interface Condition {
* re-acquire the lock associated with this condition. When the
* thread returns it is <em>guaranteed</em> to hold this lock.
*
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
@ -408,7 +407,6 @@ public interface Condition {
* case, whether or not the test for interruption occurs before the lock
* is released.
*
*
* <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows:
* <pre> {@code

View File

@ -35,6 +35,8 @@
package java.util.concurrent.locks;
import jdk.internal.misc.Unsafe;
/**
* Basic thread blocking primitives for creating locks and other
* synchronization classes.
@ -405,16 +407,30 @@ public class LockSupport {
return r;
}
/**
* Returns the thread id for the given thread. We must access
* this directly rather than via method Thread.getId() because
* getId() is not final, and has been known to be overridden in
* ways that do not preserve unique mappings.
*/
static final long getThreadId(Thread thread) {
return U.getLongVolatile(thread, TID);
}
// Hotspot implementation via intrinsics API
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final Unsafe U = Unsafe.getUnsafe();
private static final long PARKBLOCKER;
private static final long SECONDARY;
private static final long TID;
static {
try {
PARKBLOCKER = U.objectFieldOffset
(Thread.class.getDeclaredField("parkBlocker"));
SECONDARY = U.objectFieldOffset
(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
TID = U.objectFieldOffset
(Thread.class.getDeclaredField("tid"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -79,7 +79,6 @@ package java.util.concurrent.locks;
* and measurement will establish whether the use of a read-write lock is
* suitable for your application.
*
*
* <p>Although the basic operation of a read-write lock is straight-forward,
* there are many policy decisions that an implementation must make, which
* may affect the effectiveness of the read-write lock in a given application.

View File

@ -118,12 +118,6 @@ public class ReentrantLock implements Lock, java.io.Serializable {
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
/**
* Performs non-fair tryLock. tryAcquire is implemented in
* subclasses, but both need nonfair try for trylock method.
@ -201,19 +195,6 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
@ReservedStackAccess
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
@ -224,11 +205,6 @@ public class ReentrantLock implements Lock, java.io.Serializable {
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
@ -288,7 +264,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
* at which time the lock hold count is set to one.
*/
public void lock() {
sync.lock();
sync.acquire(1);
}
/**

View File

@ -37,6 +37,7 @@ package java.util.concurrent.locks;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* An implementation of {@link ReadWriteLock} supporting similar
@ -278,7 +279,7 @@ public class ReentrantReadWriteLock
static final class HoldCounter {
int count; // initially 0
// Use id, not reference, to avoid garbage retention
final long tid = getThreadId(Thread.currentThread());
final long tid = LockSupport.getThreadId(Thread.currentThread());
}
/**
@ -367,7 +368,7 @@ public class ReentrantReadWriteLock
* both read and write holds that are all released during a
* condition wait and re-established in tryAcquire.
*/
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
@ -379,6 +380,7 @@ public class ReentrantReadWriteLock
return free;
}
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
/*
* Walkthrough:
@ -411,6 +413,7 @@ public class ReentrantReadWriteLock
return true;
}
@ReservedStackAccess
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
@ -421,7 +424,8 @@ public class ReentrantReadWriteLock
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
if (rh == null ||
rh.tid != LockSupport.getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
@ -447,6 +451,7 @@ public class ReentrantReadWriteLock
"attempt to unlock read lock, not locked by current thread");
}
@ReservedStackAccess
protected final int tryAcquireShared(int unused) {
/*
* Walkthrough:
@ -479,7 +484,8 @@ public class ReentrantReadWriteLock
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
if (rh == null ||
rh.tid != LockSupport.getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@ -516,7 +522,8 @@ public class ReentrantReadWriteLock
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
if (rh == null ||
rh.tid != LockSupport.getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
@ -537,7 +544,8 @@ public class ReentrantReadWriteLock
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
if (rh == null ||
rh.tid != LockSupport.getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@ -554,6 +562,7 @@ public class ReentrantReadWriteLock
* This is identical in effect to tryAcquire except for lack
* of calls to writerShouldBlock.
*/
@ReservedStackAccess
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
@ -575,6 +584,7 @@ public class ReentrantReadWriteLock
* This is identical in effect to tryAcquireShared except for
* lack of calls to readerShouldBlock.
*/
@ReservedStackAccess
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
@ -593,7 +603,8 @@ public class ReentrantReadWriteLock
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
if (rh == null ||
rh.tid != LockSupport.getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
@ -644,7 +655,7 @@ public class ReentrantReadWriteLock
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == getThreadId(current))
if (rh != null && rh.tid == LockSupport.getThreadId(current))
return rh.count;
int count = readHolds.get().count;
@ -1490,26 +1501,4 @@ public class ReentrantReadWriteLock
"[Write locks = " + w + ", Read locks = " + r + "]";
}
/**
* Returns the thread id for the given thread. We must access
* this directly rather than via method Thread.getId() because
* getId() is not final, and has been known to be overridden in
* ways that do not preserve unique mappings.
*/
static final long getThreadId(Thread thread) {
return U.getLongVolatile(thread, TID);
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long TID;
static {
try {
TID = U.objectFieldOffset
(Thread.class.getDeclaredField("tid"));
} catch (ReflectiveOperationException e) {
throw new Error(e);
}
}
}

View File

@ -35,7 +35,10 @@
package java.util.concurrent.locks;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.TimeUnit;
import jdk.internal.vm.annotation.ReservedStackAccess;
/**
* A capability-based lock with three modes for controlling read/write
@ -108,6 +111,10 @@ import java.util.concurrent.TimeUnit;
* into initial unlocked state, so they are not useful for remote
* locking.
*
* <p>Like {@link java.util.concurrent.Semaphore Semaphore}, but unlike most
* {@link Lock} implementations, StampedLocks have no notion of ownership.
* Locks acquired in one thread can be released or converted in another.
*
* <p>The scheduling policy of StampedLock does not consistently
* prefer readers over writers or vice versa. All "try" methods are
* best-effort and do not necessarily conform to any scheduling or
@ -126,7 +133,7 @@ import java.util.concurrent.TimeUnit;
* in a class that maintains simple two-dimensional points. The sample
* code illustrates some try/catch conventions even though they are
* not strictly needed here because no exceptions can occur in their
* bodies.<br>
* bodies.
*
* <pre> {@code
* class Point {
@ -234,9 +241,7 @@ public class StampedLock implements java.io.Serializable {
* used in the acquire methods to reduce (increasingly expensive)
* context switching while also avoiding sustained memory
* thrashing among many threads. We limit spins to the head of
* queue. A thread spin-waits up to SPINS times (where each
* iteration decreases spin count with 50% probability) before
* blocking. If, upon wakening it fails to obtain lock, and is
* queue. If, upon wakening, a thread fails to obtain lock, and is
* still (or becomes) the first waiting thread (which indicates
* that some other thread barged and obtained lock), it escalates
* spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
@ -252,7 +257,7 @@ public class StampedLock implements java.io.Serializable {
* to normal volatile reads (of "state"). To force orderings of
* reads before a validation and the validation itself in those
* cases where this is not already forced, we use
* Unsafe.loadFence.
* VarHandle.acquireFence.
*
* The memory layout keeps lock state and queue pointers together
* (normally on the same cache line). This usually works well for
@ -290,7 +295,20 @@ public class StampedLock implements java.io.Serializable {
private static final long ABITS = RBITS | WBIT;
private static final long SBITS = ~RBITS; // note overlap with ABITS
// Initial value for lock state; avoid failure value zero
/*
* 3 stamp modes can be distinguished by examining (m = stamp & ABITS):
* write mode: m == WBIT
* optimistic read mode: m == 0L (even when read lock is held)
* read mode: m > 0L && m <= RFULL (the stamp is a copy of state, but the
* read hold count in the stamp is unused other than to determine mode)
*
* This differs slightly from the encoding of state:
* (state & ABITS) == 0L indicates the lock is currently unlocked.
* (state & ABITS) == RBITS is a special transient value
* indicating spin-locked to manipulate reader bits overflow.
*/
/** Initial value for lock state; avoids failure value zero. */
private static final long ORIGIN = WBIT << 1;
// Special value from cancelled acquire methods so caller can throw IE
@ -341,25 +359,27 @@ public class StampedLock implements java.io.Serializable {
* Exclusively acquires the lock, blocking if necessary
* until available.
*
* @return a stamp that can be used to unlock or convert mode
* @return a write stamp that can be used to unlock or convert mode
*/
@ReservedStackAccess
public long writeLock() {
long s, next; // bypass acquireWrite in fully unlocked case only
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
STATE.compareAndSet(this, s, next = s + WBIT)) ?
next : acquireWrite(false, 0L));
}
/**
* Exclusively acquires the lock if it is immediately available.
*
* @return a stamp that can be used to unlock or convert mode,
* @return a write stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
*/
@ReservedStackAccess
public long tryWriteLock() {
long s, next;
return ((((s = state) & ABITS) == 0L &&
U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
STATE.compareAndSet(this, s, next = s + WBIT)) ?
next : 0L);
}
@ -371,7 +391,7 @@ public class StampedLock implements java.io.Serializable {
*
* @param time the maximum time to wait for the lock
* @param unit the time unit of the {@code time} argument
* @return a stamp that can be used to unlock or convert mode,
* @return a write stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
@ -399,10 +419,11 @@ public class StampedLock implements java.io.Serializable {
* Behavior under interruption matches that specified
* for method {@link Lock#lockInterruptibly()}.
*
* @return a stamp that can be used to unlock or convert mode
* @return a write stamp that can be used to unlock or convert mode
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
*/
@ReservedStackAccess
public long writeLockInterruptibly() throws InterruptedException {
long next;
if (!Thread.interrupted() &&
@ -415,33 +436,34 @@ public class StampedLock implements java.io.Serializable {
* Non-exclusively acquires the lock, blocking if necessary
* until available.
*
* @return a stamp that can be used to unlock or convert mode
* @return a read stamp that can be used to unlock or convert mode
*/
@ReservedStackAccess
public long readLock() {
long s = state, next; // bypass acquireRead on common uncontended case
return ((whead == wtail && (s & ABITS) < RFULL &&
U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
STATE.compareAndSet(this, s, next = s + RUNIT)) ?
next : acquireRead(false, 0L));
}
/**
* Non-exclusively acquires the lock if it is immediately available.
*
* @return a stamp that can be used to unlock or convert mode,
* @return a read stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
*/
@ReservedStackAccess
public long tryReadLock() {
for (;;) {
long s, m, next;
if ((m = (s = state) & ABITS) == WBIT)
return 0L;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
long s, m, next;
while ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL) {
if (STATE.compareAndSet(this, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
return 0L;
}
/**
@ -452,11 +474,12 @@ public class StampedLock implements java.io.Serializable {
*
* @param time the maximum time to wait for the lock
* @param unit the time unit of the {@code time} argument
* @return a stamp that can be used to unlock or convert mode,
* @return a read stamp that can be used to unlock or convert mode,
* or zero if the lock is not available
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
*/
@ReservedStackAccess
public long tryReadLock(long time, TimeUnit unit)
throws InterruptedException {
long s, m, next, deadline;
@ -464,7 +487,7 @@ public class StampedLock implements java.io.Serializable {
if (!Thread.interrupted()) {
if ((m = (s = state) & ABITS) != WBIT) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
if (STATE.compareAndSet(this, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
@ -486,10 +509,11 @@ public class StampedLock implements java.io.Serializable {
* Behavior under interruption matches that specified
* for method {@link Lock#lockInterruptibly()}.
*
* @return a stamp that can be used to unlock or convert mode
* @return a read stamp that can be used to unlock or convert mode
* @throws InterruptedException if the current thread is interrupted
* before acquiring the lock
*/
@ReservedStackAccess
public long readLockInterruptibly() throws InterruptedException {
long next;
if (!Thread.interrupted() &&
@ -502,7 +526,7 @@ public class StampedLock implements java.io.Serializable {
* Returns a stamp that can later be validated, or zero
* if exclusively locked.
*
* @return a stamp, or zero if exclusively locked
* @return a valid optimistic read stamp, or zero if exclusively locked
*/
public long tryOptimisticRead() {
long s;
@ -522,10 +546,28 @@ public class StampedLock implements java.io.Serializable {
* since issuance of the given stamp; else false
*/
public boolean validate(long stamp) {
U.loadFence();
VarHandle.acquireFence();
return (stamp & SBITS) == (state & SBITS);
}
/**
* Returns an unlocked state, incrementing the version and
* avoiding special failure value 0L.
*
* @param s a write-locked state (or stamp)
*/
private static long unlockWriteState(long s) {
return ((s += WBIT) == 0L) ? ORIGIN : s;
}
private long unlockWriteInternal(long s) {
long next; WNode h;
STATE.setVolatile(this, next = unlockWriteState(s));
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
/**
* If the lock state matches the given stamp, releases the
* exclusive lock.
@ -534,13 +576,11 @@ public class StampedLock implements java.io.Serializable {
* @throws IllegalMonitorStateException if the stamp does
* not match the current state of this lock
*/
@ReservedStackAccess
public void unlockWrite(long stamp) {
WNode h;
if (state != stamp || (stamp & WBIT) == 0L)
throw new IllegalMonitorStateException();
U.putLongVolatile(this, STATE, (stamp += WBIT) == 0L ? ORIGIN : stamp);
if ((h = whead) != null && h.status != 0)
release(h);
unlockWriteInternal(stamp);
}
/**
@ -551,22 +591,23 @@ public class StampedLock implements java.io.Serializable {
* @throws IllegalMonitorStateException if the stamp does
* not match the current state of this lock
*/
@ReservedStackAccess
public void unlockRead(long stamp) {
long s, m; WNode h;
for (;;) {
if (((s = state) & SBITS) != (stamp & SBITS) ||
(stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
throw new IllegalMonitorStateException();
while (((s = state) & SBITS) == (stamp & SBITS)
&& (stamp & RBITS) > 0L
&& ((m = s & RBITS) > 0L)) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (STATE.compareAndSet(this, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
return;
}
}
else if (tryDecReaderOverflow(s) != 0L)
break;
return;
}
throw new IllegalMonitorStateException();
}
/**
@ -577,32 +618,12 @@ public class StampedLock implements java.io.Serializable {
* @throws IllegalMonitorStateException if the stamp does
* not match the current state of this lock
*/
@ReservedStackAccess
public void unlock(long stamp) {
long a = stamp & ABITS, m, s; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L)
break;
else if (m == WBIT) {
if (a != m)
break;
U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
if ((h = whead) != null && h.status != 0)
release(h);
return;
}
else if (a == 0L || a >= WBIT)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return;
}
}
else if (tryDecReaderOverflow(s) != 0L)
return;
}
throw new IllegalMonitorStateException();
if ((stamp & WBIT) != 0)
unlockWrite(stamp);
else
unlockRead(stamp);
}
/**
@ -623,7 +644,7 @@ public class StampedLock implements java.io.Serializable {
if ((m = s & ABITS) == 0L) {
if (a != 0L)
break;
if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
if (STATE.compareAndSet(this, s, next = s + WBIT))
return next;
}
else if (m == WBIT) {
@ -632,8 +653,7 @@ public class StampedLock implements java.io.Serializable {
return stamp;
}
else if (m == RUNIT && a != 0L) {
if (U.compareAndSwapLong(this, STATE, s,
next = s - RUNIT + WBIT))
if (STATE.compareAndSet(this, s, next = s - RUNIT + WBIT))
return next;
}
else
@ -654,30 +674,32 @@ public class StampedLock implements java.io.Serializable {
* @return a valid read stamp, or zero on failure
*/
public long tryConvertToReadLock(long stamp) {
long a = stamp & ABITS, m, s, next; WNode h;
long a, s, next; WNode h;
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((m = s & ABITS) == 0L) {
if (a != 0L)
if ((a = stamp & ABITS) >= WBIT) {
// write stamp
if (s != stamp)
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
STATE.setVolatile(this, next = unlockWriteState(s) + RUNIT);
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
else if (a == 0L) {
// optimistic read stamp
if ((s & ABITS) < RFULL) {
if (STATE.compareAndSet(this, s, next = s + RUNIT))
return next;
}
else if ((next = tryIncReaderOverflow(s)) != 0L)
return next;
}
else if (m == WBIT) {
if (a != m)
else {
// already a read stamp
if ((s & ABITS) == 0L)
break;
U.putLongVolatile(this, STATE, next = s + (WBIT + RUNIT));
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
else if (a != 0L && a < WBIT)
return stamp;
else
break;
}
}
return 0L;
}
@ -693,29 +715,22 @@ public class StampedLock implements java.io.Serializable {
* @return a valid optimistic read stamp, or zero on failure
*/
public long tryConvertToOptimisticRead(long stamp) {
long a = stamp & ABITS, m, s, next; WNode h;
U.loadFence();
for (;;) {
if (((s = state) & SBITS) != (stamp & SBITS))
break;
if ((m = s & ABITS) == 0L) {
if (a != 0L)
long a, m, s, next; WNode h;
VarHandle.acquireFence();
while (((s = state) & SBITS) == (stamp & SBITS)) {
if ((a = stamp & ABITS) >= WBIT) {
// write stamp
if (s != stamp)
break;
return s;
return unlockWriteInternal(s);
}
else if (m == WBIT) {
if (a != m)
break;
U.putLongVolatile(this, STATE,
next = (s += WBIT) == 0L ? ORIGIN : s);
if ((h = whead) != null && h.status != 0)
release(h);
return next;
}
else if (a == 0L || a >= WBIT)
else if (a == 0L)
// already an optimistic read stamp
return stamp;
else if ((m = s & ABITS) == 0L) // invalid read stamp
break;
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
if (STATE.compareAndSet(this, s, next = s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return next & SBITS;
@ -734,12 +749,11 @@ public class StampedLock implements java.io.Serializable {
*
* @return {@code true} if the lock was held, else false
*/
@ReservedStackAccess
public boolean tryUnlockWrite() {
long s; WNode h;
long s;
if (((s = state) & WBIT) != 0L) {
U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
if ((h = whead) != null && h.status != 0)
release(h);
unlockWriteInternal(s);
return true;
}
return false;
@ -752,11 +766,12 @@ public class StampedLock implements java.io.Serializable {
*
* @return {@code true} if the read lock was held, else false
*/
@ReservedStackAccess
public boolean tryUnlockRead() {
long s, m; WNode h;
while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
if (STATE.compareAndSet(this, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
return true;
@ -832,32 +847,30 @@ public class StampedLock implements java.io.Serializable {
* Returns a plain {@link Lock} view of this StampedLock in which
* the {@link Lock#lock} method is mapped to {@link #readLock},
* and similarly for other methods. The returned Lock does not
* support a {@link Condition}; method {@link
* Lock#newCondition()} throws {@code
* UnsupportedOperationException}.
* support a {@link Condition}; method {@link Lock#newCondition()}
* throws {@code UnsupportedOperationException}.
*
* @return the lock
*/
public Lock asReadLock() {
ReadLockView v;
return ((v = readLockView) != null ? v :
(readLockView = new ReadLockView()));
if ((v = readLockView) != null) return v;
return readLockView = new ReadLockView();
}
/**
* Returns a plain {@link Lock} view of this StampedLock in which
* the {@link Lock#lock} method is mapped to {@link #writeLock},
* and similarly for other methods. The returned Lock does not
* support a {@link Condition}; method {@link
* Lock#newCondition()} throws {@code
* UnsupportedOperationException}.
* support a {@link Condition}; method {@link Lock#newCondition()}
* throws {@code UnsupportedOperationException}.
*
* @return the lock
*/
public Lock asWriteLock() {
WriteLockView v;
return ((v = writeLockView) != null ? v :
(writeLockView = new WriteLockView()));
if ((v = writeLockView) != null) return v;
return writeLockView = new WriteLockView();
}
/**
@ -870,8 +883,8 @@ public class StampedLock implements java.io.Serializable {
*/
public ReadWriteLock asReadWriteLock() {
ReadWriteLockView v;
return ((v = readWriteLockView) != null ? v :
(readWriteLockView = new ReadWriteLockView()));
if ((v = readWriteLockView) != null) return v;
return readWriteLockView = new ReadWriteLockView();
}
// view classes
@ -917,35 +930,32 @@ public class StampedLock implements java.io.Serializable {
// Needed because view-class lock methods throw away stamps.
final void unstampedUnlockWrite() {
WNode h; long s;
long s;
if (((s = state) & WBIT) == 0L)
throw new IllegalMonitorStateException();
U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
if ((h = whead) != null && h.status != 0)
release(h);
unlockWriteInternal(s);
}
final void unstampedUnlockRead() {
for (;;) {
long s, m; WNode h;
if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
throw new IllegalMonitorStateException();
else if (m < RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
long s, m; WNode h;
while ((m = (s = state) & RBITS) > 0L) {
if (m < RFULL) {
if (STATE.compareAndSet(this, s, s - RUNIT)) {
if (m == RUNIT && (h = whead) != null && h.status != 0)
release(h);
break;
return;
}
}
else if (tryDecReaderOverflow(s) != 0L)
break;
return;
}
throw new IllegalMonitorStateException();
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
U.putLongVolatile(this, STATE, ORIGIN); // reset to unlocked state
STATE.setVolatile(this, ORIGIN); // reset to unlocked state
}
// internals
@ -961,15 +971,16 @@ public class StampedLock implements java.io.Serializable {
private long tryIncReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
if (STATE.compareAndSet(this, s, s | RBITS)) {
++readerOverflow;
U.putLongVolatile(this, STATE, s);
STATE.setVolatile(this, s);
return s;
}
}
else if ((LockSupport.nextSecondarySeed() &
OVERFLOW_YIELD_RATE) == 0)
else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
else
Thread.onSpinWait();
return 0L;
}
@ -982,7 +993,7 @@ public class StampedLock implements java.io.Serializable {
private long tryDecReaderOverflow(long s) {
// assert (s & ABITS) >= RFULL;
if ((s & ABITS) == RFULL) {
if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
if (STATE.compareAndSet(this, s, s | RBITS)) {
int r; long next;
if ((r = readerOverflow) > 0) {
readerOverflow = r - 1;
@ -990,13 +1001,14 @@ public class StampedLock implements java.io.Serializable {
}
else
next = s - RUNIT;
U.putLongVolatile(this, STATE, next);
STATE.setVolatile(this, next);
return next;
}
}
else if ((LockSupport.nextSecondarySeed() &
OVERFLOW_YIELD_RATE) == 0)
else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
else
Thread.onSpinWait();
return 0L;
}
@ -1010,14 +1022,14 @@ public class StampedLock implements java.io.Serializable {
private void release(WNode h) {
if (h != null) {
WNode q; Thread w;
U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
WSTATUS.compareAndSet(h, WAITING, 0);
if ((q = h.next) == null || q.status == CANCELLED) {
for (WNode t = wtail; t != null && t != h; t = t.prev)
if (t.status <= 0)
q = t;
}
if (q != null && (w = q.thread) != null)
U.unpark(w);
LockSupport.unpark(w);
}
}
@ -1035,25 +1047,25 @@ public class StampedLock implements java.io.Serializable {
for (int spins = -1;;) { // spin while enqueuing
long m, s, ns;
if ((m = (s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
if (STATE.compareAndSet(this, s, ns = s + WBIT))
return ns;
}
else if (spins < 0)
spins = (m == WBIT && wtail == whead) ? SPINS : 0;
else if (spins > 0) {
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
--spins;
Thread.onSpinWait();
}
else if ((p = wtail) == null) { // initialize queue
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
if (WHEAD.weakCompareAndSetVolatile(this, null, hd))
wtail = hd;
}
else if (node == null)
node = new WNode(WMODE, p);
else if (node.prev != p)
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
else if (WTAIL.weakCompareAndSetVolatile(this, p, node)) {
p.next = node;
break;
}
@ -1067,11 +1079,10 @@ public class StampedLock implements java.io.Serializable {
spins = HEAD_SPINS;
else if (spins < MAX_HEAD_SPINS)
spins <<= 1;
for (int k = spins;;) { // spin at head
for (int k = spins; k > 0; --k) { // spin at head
long s, ns;
if (((s = state) & ABITS) == 0L) {
if (U.compareAndSwapLong(this, STATE, s,
ns = s + WBIT)) {
if (STATE.compareAndSet(this, s, ns = s + WBIT)) {
whead = node;
node.prev = null;
if (wasInterrupted)
@ -1079,17 +1090,16 @@ public class StampedLock implements java.io.Serializable {
return ns;
}
}
else if (LockSupport.nextSecondarySeed() >= 0 &&
--k <= 0)
break;
else
Thread.onSpinWait();
}
}
else if (h != null) { // help release stale waiters
WNode c; Thread w;
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
if (WCOWAIT.weakCompareAndSetVolatile(h, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
LockSupport.unpark(w);
}
}
if (whead == h) {
@ -1098,7 +1108,7 @@ public class StampedLock implements java.io.Serializable {
(p = np).next = node; // stale
}
else if ((ps = p.status) == 0)
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
WSTATUS.compareAndSet(p, 0, WAITING);
else if (ps == CANCELLED) {
if ((pp = p.prev) != null) {
node.prev = pp;
@ -1112,13 +1122,15 @@ public class StampedLock implements java.io.Serializable {
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
whead == h && node.prev == p)
U.park(false, time); // emulate LockSupport.park
whead == h && node.prev == p) {
if (time == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, time);
}
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (Thread.interrupted()) {
if (interruptible)
return cancelWaiter(node, node, true);
@ -1146,7 +1158,7 @@ public class StampedLock implements java.io.Serializable {
if ((h = whead) == (p = wtail)) {
for (long m, s, ns;;) {
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
STATE.compareAndSet(this, s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
if (wasInterrupted)
Thread.currentThread().interrupt();
@ -1154,8 +1166,8 @@ public class StampedLock implements java.io.Serializable {
}
else if (m >= WBIT) {
if (spins > 0) {
if (LockSupport.nextSecondarySeed() >= 0)
--spins;
--spins;
Thread.onSpinWait();
}
else {
if (spins == 0) {
@ -1170,7 +1182,7 @@ public class StampedLock implements java.io.Serializable {
}
if (p == null) { // initialize queue
WNode hd = new WNode(WMODE, null);
if (U.compareAndSwapObject(this, WHEAD, null, hd))
if (WHEAD.weakCompareAndSetVolatile(this, null, hd))
wtail = hd;
}
else if (node == null)
@ -1178,27 +1190,25 @@ public class StampedLock implements java.io.Serializable {
else if (h == p || p.mode != RMODE) {
if (node.prev != p)
node.prev = p;
else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
else if (WTAIL.weakCompareAndSetVolatile(this, p, node)) {
p.next = node;
break;
}
}
else if (!U.compareAndSwapObject(p, WCOWAIT,
node.cowait = p.cowait, node))
else if (!WCOWAIT.compareAndSet(p, node.cowait = p.cowait, node))
node.cowait = null;
else {
for (;;) {
WNode pp, c; Thread w;
if ((h = whead) != null && (c = h.cowait) != null &&
U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
WCOWAIT.compareAndSet(h, c, c.cowait) &&
(w = c.thread) != null) // help release
U.unpark(w);
LockSupport.unpark(w);
if (h == (pp = p.prev) || h == p || pp == null) {
long m, s, ns;
do {
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s,
ns = s + RUNIT) :
STATE.compareAndSet(this, s, ns = s + RUNIT) :
(m < WBIT &&
(ns = tryIncReaderOverflow(s)) != 0L)) {
if (wasInterrupted)
@ -1221,13 +1231,15 @@ public class StampedLock implements java.io.Serializable {
return cancelWaiter(node, p, false);
}
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if ((h != pp || (state & ABITS) == WBIT) &&
whead == h && p.prev == pp)
U.park(false, time);
whead == h && p.prev == pp) {
if (time == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, time);
}
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (Thread.interrupted()) {
if (interruptible)
return cancelWaiter(node, p, true);
@ -1248,32 +1260,32 @@ public class StampedLock implements java.io.Serializable {
for (int k = spins;;) { // spin at head
long m, s, ns;
if ((m = (s = state) & ABITS) < RFULL ?
U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
STATE.compareAndSet(this, s, ns = s + RUNIT) :
(m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
WNode c; Thread w;
whead = node;
node.prev = null;
while ((c = node.cowait) != null) {
if (U.compareAndSwapObject(node, WCOWAIT,
c, c.cowait) &&
if (WCOWAIT.compareAndSet(node, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
LockSupport.unpark(w);
}
if (wasInterrupted)
Thread.currentThread().interrupt();
return ns;
}
else if (m >= WBIT &&
LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
else if (m >= WBIT && --k <= 0)
break;
else
Thread.onSpinWait();
}
}
else if (h != null) {
WNode c; Thread w;
while ((c = h.cowait) != null) {
if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
if (WCOWAIT.compareAndSet(h, c, c.cowait) &&
(w = c.thread) != null)
U.unpark(w);
LockSupport.unpark(w);
}
}
if (whead == h) {
@ -1282,7 +1294,7 @@ public class StampedLock implements java.io.Serializable {
(p = np).next = node; // stale
}
else if ((ps = p.status) == 0)
U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
WSTATUS.compareAndSet(p, 0, WAITING);
else if (ps == CANCELLED) {
if ((pp = p.prev) != null) {
node.prev = pp;
@ -1296,14 +1308,16 @@ public class StampedLock implements java.io.Serializable {
else if ((time = deadline - System.nanoTime()) <= 0L)
return cancelWaiter(node, node, false);
Thread wt = Thread.currentThread();
U.putObject(wt, PARKBLOCKER, this);
node.thread = wt;
if (p.status < 0 &&
(p != h || (state & ABITS) == WBIT) &&
whead == h && node.prev == p)
U.park(false, time);
whead == h && node.prev == p) {
if (time == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, time);
}
node.thread = null;
U.putObject(wt, PARKBLOCKER, null);
if (Thread.interrupted()) {
if (interruptible)
return cancelWaiter(node, node, true);
@ -1325,7 +1339,7 @@ public class StampedLock implements java.io.Serializable {
* AbstractQueuedSynchronizer (see its detailed explanation in AQS
* internal documentation).
*
* @param node if nonnull, the waiter
* @param node if non-null, the waiter
* @param group either node or the group node is cowaiting with
* @param interrupted if already interrupted
* @return INTERRUPTED if interrupted or Thread.interrupted, else zero
@ -1337,7 +1351,7 @@ public class StampedLock implements java.io.Serializable {
// unsplice cancelled nodes from group
for (WNode p = group, q; (q = p.cowait) != null;) {
if (q.status == CANCELLED) {
U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
WCOWAIT.compareAndSet(p, q, q.cowait);
p = group; // restart
}
else
@ -1346,7 +1360,7 @@ public class StampedLock implements java.io.Serializable {
if (group == node) {
for (WNode r = group.cowait; r != null; r = r.cowait) {
if ((w = r.thread) != null)
U.unpark(w); // wake up uncancelled co-waiters
LockSupport.unpark(w); // wake up uncancelled co-waiters
}
for (WNode pred = node.prev; pred != null; ) { // unsplice
WNode succ, pp; // find valid successor
@ -1357,23 +1371,23 @@ public class StampedLock implements java.io.Serializable {
if (t.status != CANCELLED)
q = t; // don't link if succ cancelled
if (succ == q || // ensure accurate successor
U.compareAndSwapObject(node, WNEXT,
succ, succ = q)) {
WNEXT.compareAndSet(node, succ, succ = q)) {
if (succ == null && node == wtail)
U.compareAndSwapObject(this, WTAIL, node, pred);
WTAIL.compareAndSet(this, node, pred);
break;
}
}
if (pred.next == node) // unsplice pred link
U.compareAndSwapObject(pred, WNEXT, node, succ);
WNEXT.compareAndSet(pred, node, succ);
if (succ != null && (w = succ.thread) != null) {
// wake up succ to observe new pred
succ.thread = null;
U.unpark(w); // wake up succ to observe new pred
LockSupport.unpark(w);
}
if (pred.status != CANCELLED || (pp = pred.prev) == null)
break;
node.prev = pp; // repeat if new pred wrong/cancelled
U.compareAndSwapObject(pp, WNEXT, pred, succ);
WNEXT.compareAndSet(pp, pred, succ);
pred = pp;
}
}
@ -1397,34 +1411,22 @@ public class StampedLock implements java.io.Serializable {
return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
}
// Unsafe mechanics
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
private static final long STATE;
private static final long WHEAD;
private static final long WTAIL;
private static final long WNEXT;
private static final long WSTATUS;
private static final long WCOWAIT;
private static final long PARKBLOCKER;
// VarHandle mechanics
private static final VarHandle STATE;
private static final VarHandle WHEAD;
private static final VarHandle WTAIL;
private static final VarHandle WNEXT;
private static final VarHandle WSTATUS;
private static final VarHandle WCOWAIT;
static {
try {
STATE = U.objectFieldOffset
(StampedLock.class.getDeclaredField("state"));
WHEAD = U.objectFieldOffset
(StampedLock.class.getDeclaredField("whead"));
WTAIL = U.objectFieldOffset
(StampedLock.class.getDeclaredField("wtail"));
WSTATUS = U.objectFieldOffset
(WNode.class.getDeclaredField("status"));
WNEXT = U.objectFieldOffset
(WNode.class.getDeclaredField("next"));
WCOWAIT = U.objectFieldOffset
(WNode.class.getDeclaredField("cowait"));
PARKBLOCKER = U.objectFieldOffset
(Thread.class.getDeclaredField("parkBlocker"));
MethodHandles.Lookup l = MethodHandles.lookup();
STATE = l.findVarHandle(StampedLock.class, "state", long.class);
WHEAD = l.findVarHandle(StampedLock.class, "whead", WNode.class);
WTAIL = l.findVarHandle(StampedLock.class, "wtail", WNode.class);
WSTATUS = l.findVarHandle(WNode.class, "status", int.class);
WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
} catch (ReflectiveOperationException e) {
throw new Error(e);
}

View File

@ -262,7 +262,6 @@
*
* </ul>
*
*
* The methods of all classes in {@code java.util.concurrent} and its
* subpackages extend these guarantees to higher-level
* synchronization. In particular:

View File

@ -20,7 +20,9 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.nio.ByteBuffer;

View File

@ -20,6 +20,7 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;

View File

@ -20,7 +20,9 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.io.IOException;

View File

@ -20,7 +20,9 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.io.Closeable;

View File

@ -20,7 +20,9 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.io.IOException;

View File

@ -20,6 +20,7 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;

View File

@ -20,6 +20,7 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;

View File

@ -20,6 +20,7 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -20,7 +20,9 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.nio.ByteBuffer;

View File

@ -20,7 +20,9 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;
import java.net.InetSocketAddress;

View File

@ -20,6 +20,7 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;

View File

@ -20,6 +20,7 @@
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net.http;

Some files were not shown because too many files have changed in this diff Show More