Merge
This commit is contained in:
commit
1aae9e05cf
@ -101,3 +101,4 @@ ac311eb325bfc763698219252bf3cee9e091f3af jdk7-b122
|
||||
1c72adc9d5f331cb882cf5354ba0dcb118a60b23 jdk7-b124
|
||||
0a56bdd709d01c1663047e55201d19152ffd3d69 jdk7-b125
|
||||
8361ef97a0f90086c9048beaf7cea1a37216c4cd jdk7-b126
|
||||
29e09de1d0b4f84faea114cf10b3ec08b59acc4e jdk7-b127
|
||||
|
@ -74,15 +74,6 @@ SCRIPT_SUFFIX =
|
||||
CC_OBJECT_OUTPUT_FLAG = -o #trailing blank required!
|
||||
CC_PROGRAM_OUTPUT_FLAG = -o #trailing blank required!
|
||||
|
||||
#
|
||||
# Default HPI libraries. Build will build only native, unless
|
||||
# overriden at the make command line. This makes it convenient for
|
||||
# people doing, say, a pthreads port -- they can create a posix
|
||||
# directory here, and say "gnumake HPIS=posix" at the top
|
||||
# level.
|
||||
#
|
||||
HPIS = native
|
||||
|
||||
#
|
||||
# Default optimization
|
||||
#
|
||||
|
@ -74,15 +74,6 @@ SCRIPT_SUFFIX =
|
||||
CC_OBJECT_OUTPUT_FLAG = -o #trailing blank required!
|
||||
CC_PROGRAM_OUTPUT_FLAG = -o #trailing blank required!
|
||||
|
||||
#
|
||||
# Default HPI libraries. Build will build only native unless
|
||||
# overriden at the make command line. This makes it convenient for
|
||||
# people doing, say, a pthreads port -- they can create a posix
|
||||
# directory here, and say "gnumake HPIS=posix" at the top
|
||||
# level.
|
||||
#
|
||||
HPIS = native
|
||||
|
||||
#
|
||||
# Java default optimization (-x04/-O2) etc. Applies to the VM.
|
||||
#
|
||||
|
@ -43,7 +43,6 @@ FDDLIBM_SUFFIX = lib
|
||||
# The suffix applied to scripts (.bat for windows, nothing for unix)
|
||||
SCRIPT_SUFFIX = .bat
|
||||
|
||||
HPIS = windows
|
||||
# LIB_LOCATION, which for windows identifies where .exe files go, may be
|
||||
# set by each GNUmakefile. The default is BINDIR.
|
||||
ifndef LIB_LOCATION
|
||||
@ -365,10 +364,6 @@ ifeq ($(CC_VERSION),msvc)
|
||||
|
||||
# LFLAGS are the flags given to $(LINK) and used to build the actual DLL file
|
||||
BASELFLAGS = -nologo /opt:REF /incremental:no
|
||||
ifdef MT
|
||||
# VS2005, VS2008, and beyond: ask LINK to generate manifests for .dll & .exe
|
||||
BASELFLAGS += /manifest
|
||||
endif
|
||||
|
||||
LFLAGS = $(BASELFLAGS) $(LDEBUG) $(EXTRA_LFLAGS) $(LFLAGS_$(COMPILER_VERSION))
|
||||
LDDFLAGS += $(LFLAGS_$(COMPILER_VERSION))
|
||||
|
@ -271,10 +271,9 @@ DEMOSRCDIR = $(SHARE_SRC)/demo
|
||||
# An attempt is made to generate unique enough directories for the
|
||||
# generated files to not have name collisisons. Most build units
|
||||
# defines PRODUCT (except Release.gmk), but then they may or may
|
||||
# not define PACKAGE, THREADIR (only HPI uses this), PROGRAM, and
|
||||
# LIBRARY. This code chunk attempts to generate a unique
|
||||
# OBJDIR/CLASSHDRDIR for each build unit based on which of those
|
||||
# values are set within each build unit.
|
||||
# not define PACKAGE, PROGRAM, and LIBRARY. This code attempts to
|
||||
# generate a unique OBJDIR/CLASSHDRDIR for each build unit based
|
||||
# on which of those values are set within each build unit.
|
||||
|
||||
UNIQUE_LOCATION_STRING = tmp
|
||||
|
||||
@ -298,10 +297,6 @@ ifneq ($(LIBRARY),)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(THREADDIR),)
|
||||
UNIQUE_LOCATION_STRING += /$(THREADDIR)
|
||||
endif
|
||||
|
||||
#
|
||||
# Build units may or may not define MODULE. Default to "other".
|
||||
#
|
||||
|
@ -73,8 +73,11 @@ DEMO_BUILD_AREA = $(DEMOCLASSDIR)/$(PRODUCT)/$(DEMONAME)
|
||||
|
||||
# Destination "src" directory
|
||||
DEMO_BUILD_SRCDIR = $(DEMO_BUILD_AREA)/src
|
||||
DEMO_BUILD_SRCZIP = $(DEMO_BUILD_AREA)/src.zip
|
||||
DEMO_SOURCE_ZIP = $(DEMO_DESTDIR)/src.zip
|
||||
|
||||
ifndef DEMO_SKIP_SRCZIP
|
||||
DEMO_BUILD_SRCZIP = $(DEMO_BUILD_AREA)/src.zip
|
||||
DEMO_SOURCE_ZIP = $(DEMO_DESTDIR)/src.zip
|
||||
endif
|
||||
|
||||
# Place to hold the jar image we are creating
|
||||
DEMO_JAR_IMAGE = $(DEMO_BUILD_AREA)/jar_image
|
||||
@ -258,14 +261,16 @@ $(DEMO_JAR): \
|
||||
|
||||
endif
|
||||
|
||||
# Create a src.zip file
|
||||
$(DEMO_BUILD_SRCZIP): $(DEMO_FULL_SOURCES)
|
||||
ifndef DEMO_SKIP_SRCZIP
|
||||
# Create a src.zip file
|
||||
$(DEMO_BUILD_SRCZIP): $(DEMO_FULL_SOURCES)
|
||||
@$(prep-target)
|
||||
$(CD) $(DEMO_BUILD_AREA)/src && $(ZIPEXE) -q -r ../$(@F) .
|
||||
|
||||
# Install the destination src.zip file and create the src tree
|
||||
$(DEMO_SOURCE_ZIP): $(DEMO_BUILD_SRCZIP)
|
||||
# Install the destination src.zip file and create the src tree
|
||||
$(DEMO_SOURCE_ZIP): $(DEMO_BUILD_SRCZIP)
|
||||
$(install-file)
|
||||
endif
|
||||
|
||||
# Native library building
|
||||
ifdef DEMO_LIBRARY
|
||||
@ -362,7 +367,7 @@ clean clobber:
|
||||
$(RM) -r $(DEMO_BUILD_AREA)
|
||||
$(RM) -r $(DEMO_DESTDIR)
|
||||
|
||||
# This should not be needed, but some versions of GNU amke have a bug that
|
||||
# This should not be needed, but some versions of GNU make have a bug that
|
||||
# sometimes deleted these files for some strange and unknown reason
|
||||
# (GNU make version 3.78.1 has the problem, GNU make version 3.80 doesn't?)
|
||||
.PRECIOUS: $(DEMO_FULL_SOURCES) $(DEMO_BUILD_SRCZIP) $(DEMO_SOURCE_ZIP)
|
||||
|
@ -159,9 +159,6 @@ else # LIBRARY
|
||||
# build it into $(OBJDIR) so that the other generated files get put
|
||||
# there, then copy just the DLL (and MAP file) to the requested directory.
|
||||
#
|
||||
# In VS2005 or VS2008 the link command creates a .manifest file that we want
|
||||
# to insert into the linked artifact so we do not need to track it separately.
|
||||
# Use ";#2" for .dll and ";#1" for .exe in the MT command below:
|
||||
$(ACTUAL_LIBRARY):: $(OBJDIR)/$(LIBRARY).lcf
|
||||
@$(prep-target)
|
||||
@$(MKDIR) -p $(OBJDIR)
|
||||
@ -169,9 +166,6 @@ $(ACTUAL_LIBRARY):: $(OBJDIR)/$(LIBRARY).lcf
|
||||
-map:$(OBJDIR)/$(LIBRARY).map \
|
||||
$(LFLAGS) @$(OBJDIR)/$(LIBRARY).lcf \
|
||||
$(OTHER_LCF) $(JAVALIB) $(LDLIBS)
|
||||
ifdef MT
|
||||
$(MT) /manifest $(OBJDIR)/$(@F).manifest /outputresource:$(OBJDIR)/$(@F);#2
|
||||
endif
|
||||
$(CP) $(OBJDIR)/$(@F) $@
|
||||
$(install-module-file)
|
||||
$(CP) $(OBJDIR)/$(LIBRARY).map $(@D)
|
||||
|
@ -222,7 +222,7 @@ ifeq ($(PLATFORM), windows)
|
||||
@# Remove certain *.lib files
|
||||
$(CD) $(JRE_MODULE_IMAGE_DIR)/lib && \
|
||||
$(RM) java.$(LIB_SUFFIX) jvm.$(LIB_SUFFIX) \
|
||||
hpi.$(LIB_SUFFIX) awt.$(LIB_SUFFIX) jawt.$(LIB_SUFFIX)
|
||||
awt.$(LIB_SUFFIX) jawt.$(LIB_SUFFIX)
|
||||
ifeq ($(ARCH_DATA_MODEL), 32)
|
||||
@# The Java Kernel JRE image ships with a special VM. It is not included
|
||||
@# in the full JRE image, so remove it. Also, is it only for 32-bit windows.
|
||||
@ -415,8 +415,7 @@ endif # !windows
|
||||
trim-module-image-jdk::
|
||||
@# Remove tools that should not be part of SDK.
|
||||
for t in $(NOTJDKTOOLS); do \
|
||||
$(RM) $(JDK_MODULE_IMAGE_DIR)/bin/$${t}$(EXE_SUFFIX) \
|
||||
$(JDK_MODULE_IMAGE_DIR)/bin/*/native_threads/$${t}$(EXE_SUFFIX); \
|
||||
$(RM) $(JDK_MODULE_IMAGE_DIR)/bin/$${t}$(EXE_SUFFIX); \
|
||||
done
|
||||
|
||||
# Get list of Elf files in the jdk
|
||||
|
@ -142,10 +142,15 @@ else
|
||||
STACK_SIZE=1048576
|
||||
endif
|
||||
|
||||
# In VS2005 or VS2008 the link command creates a .manifest file that we want
|
||||
# to insert into the linked artifact so we do not need to track it separately.
|
||||
IMVERSION=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER)
|
||||
$(OBJDIR)/$(PROGRAM).exe.manifest: $(JDK_TOPDIR)/src/windows/resource/java.manifest
|
||||
@$(prep-target)
|
||||
$(SED) 's%IMVERSION%$(IMVERSION)%g;s%PROGRAM%$(PROGRAM)%g' $< > $@
|
||||
|
||||
# We used a hand-crafted manifest file for all executables.
|
||||
# It is tweaked to embed the build number and executable name.
|
||||
# Use ";#2" for .dll and ";#1" for .exe in the MT command below:
|
||||
$(OBJDIR)/$(PROGRAM)$(EXE_SUFFIX):: $(OBJDIR)/$(PROGRAM).lcf $(FILES_o) $(JLI_LCF)
|
||||
$(OBJDIR)/$(PROGRAM)$(EXE_SUFFIX):: $(OBJDIR)/$(PROGRAM).lcf $(FILES_o) $(JLI_LCF) $(OBJDIR)/$(PROGRAM).exe.manifest
|
||||
@$(prep-target)
|
||||
@set -- $?; \
|
||||
$(ECHO) Rebuilding $@ because of $$1 $$2 $$3 $$4 $$5 $$6 $${7:+...};
|
||||
|
@ -133,7 +133,6 @@ JRE_DOCFILES += $(JRE_NAMECHANGE_DOCLIST:%=$(JRE_IMAGE_DIR)/%$(TEXT_SUFFIX))
|
||||
# absolute directory names: note, these must exist prior to build
|
||||
# time - they are created in the main Makefile.
|
||||
JRE_IMAGE_BINDIR = $(JRE_IMAGE_DIR)/bin
|
||||
JRE_IMAGE_THREADIR = $(JRE_IMAGE_DIR)/bin/*/native_threads
|
||||
|
||||
MAINMANIFEST = $(JDK_TOPDIR)/make/tools/manifest.mf
|
||||
BEANMANIFEST = $(JDK_TOPDIR)/make/javax/swing/beaninfo/manifest
|
||||
@ -802,7 +801,7 @@ ifeq ($(PLATFORM), windows)
|
||||
@# Remove certain *.lib files
|
||||
$(CD) $(JRE_IMAGE_DIR)/lib && \
|
||||
$(RM) java.$(LIB_SUFFIX) jvm.$(LIB_SUFFIX) \
|
||||
hpi.$(LIB_SUFFIX) awt.$(LIB_SUFFIX) jawt.$(LIB_SUFFIX)
|
||||
awt.$(LIB_SUFFIX) jawt.$(LIB_SUFFIX)
|
||||
ifeq ($(ARCH_DATA_MODEL), 32)
|
||||
@# The Java Kernel JRE image ships with a special VM. It is not included
|
||||
@# in the full JRE image, so remove it. Also, is it only for 32-bit windows.
|
||||
@ -1089,8 +1088,7 @@ endif # !windows
|
||||
trim-image-jdk::
|
||||
@# Remove tools that should not be part of SDK.
|
||||
for t in $(NOTJDKTOOLS); do \
|
||||
$(RM) $(JDK_IMAGE_DIR)/bin/$${t}$(EXE_SUFFIX) \
|
||||
$(JDK_IMAGE_DIR)/bin/*/native_threads/$${t}$(EXE_SUFFIX); \
|
||||
$(RM) $(JDK_IMAGE_DIR)/bin/$${t}$(EXE_SUFFIX); \
|
||||
done
|
||||
|
||||
# Get list of Elf files in the jdk
|
||||
|
@ -34,7 +34,7 @@ include $(BUILDDIR)/common/Defs.gmk
|
||||
#
|
||||
# The order of subdirs here is important
|
||||
#
|
||||
SUBDIRS += hpi version jvm redist verify fdlibm java sun_nio jli main zip
|
||||
SUBDIRS += version jvm redist verify fdlibm java sun_nio jli main zip
|
||||
|
||||
# Others
|
||||
# Note: java_crw_demo java_hprof_demo are demos but must be delivered built in sdk
|
||||
|
@ -24,7 +24,7 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Makefile for native threads HPI.
|
||||
# Makefile for fdlibm
|
||||
#
|
||||
# Note:
|
||||
# The fdlibm libraries are built using special rules in Library.gmk.
|
||||
|
@ -1,90 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 1998, 2010, 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Shared files between the different threads types on Solaris. Be
|
||||
# careful when including this, you must get your variables right.
|
||||
#
|
||||
|
||||
#
|
||||
# Common files on Solaris.
|
||||
#
|
||||
ifneq ($(PLATFORM), windows)
|
||||
FILES_c += \
|
||||
interrupt.c \
|
||||
linker_md.c \
|
||||
memory_md.c \
|
||||
system_md.c \
|
||||
hpi.c
|
||||
endif
|
||||
|
||||
#
|
||||
# Include paths can also be shared.
|
||||
#
|
||||
ifneq ($(PLATFORM), windows)
|
||||
OTHER_INCLUDES += \
|
||||
-I$(PLATFORM_SRC)/hpi/$(THREADDIR)/include \
|
||||
-I$(PLATFORM_SRC)/hpi/include \
|
||||
-I$(PLATFORM_SRC)/hpi/export \
|
||||
-I$(SHARE_SRC)/hpi/include \
|
||||
-I$(SHARE_SRC)/hpi/export
|
||||
else
|
||||
OTHER_INCLUDES += \
|
||||
-I$(PLATFORM_SRC)/hpi/include \
|
||||
-I$(PLATFORM_SRC)/hpi/export \
|
||||
-I$(SHARE_SRC)/hpi/include \
|
||||
-I$(SHARE_SRC)/hpi/export
|
||||
endif
|
||||
|
||||
#
|
||||
# Add to the default C and assembly file search paths. Clear any initial
|
||||
# vpath settings to ensure that we don't look in unexpected places for HPI
|
||||
# files.
|
||||
#
|
||||
vpath %.c
|
||||
vpath %.c $(PLATFORM_SRC)/hpi/$(THREADDIR)/src
|
||||
vpath %.c $(PLATFORM_SRC)/hpi/src
|
||||
vpath %.c $(SHARE_SRC)/hpi/src
|
||||
|
||||
vpath %.s
|
||||
vpath %.s $(PLATFORM_SRC)/hpi/$(THREADDIR)/src
|
||||
vpath %.s $(PLATFORM_SRC)/hpi/src
|
||||
|
||||
#
|
||||
# By default leave out locking statistics
|
||||
#
|
||||
ifneq ($(PLATFORM), windows)
|
||||
LOCKSTATS = false
|
||||
ifeq ($(LOCKSTATS), true)
|
||||
CFLAGS_COMMON += -DLOCKSTATS
|
||||
endif
|
||||
endif
|
||||
|
||||
#
|
||||
# Things that must be linked in.
|
||||
#
|
||||
ifneq ($(PLATFORM), windows)
|
||||
OTHER_LDLIBS += $(LIBSOCKET) $(LIBNSL) $(LIBM) -ldl
|
||||
endif
|
@ -1,93 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 1998, 2010, 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Makefile for native threads HPI.
|
||||
#
|
||||
|
||||
BUILDDIR = ../../..
|
||||
MODULE = base
|
||||
LIBRARY = hpi
|
||||
PRODUCT = java
|
||||
THREADDIR = native_threads
|
||||
LIB_LOCATION = $(LIBDIR)/$(LIBARCH)/$(THREADDIR)
|
||||
include $(BUILDDIR)/common/Defs.gmk
|
||||
|
||||
#
|
||||
# Native threads specific C and .s files.
|
||||
#
|
||||
FILES_c = \
|
||||
monitor_md.c \
|
||||
threads_md.c \
|
||||
condvar_md.c \
|
||||
interrupt_md.c \
|
||||
mutex_md.c \
|
||||
sys_api_td.c \
|
||||
threads_$(PLATFORM).c
|
||||
|
||||
#
|
||||
# Other files/flags shared between the HPIs.
|
||||
#
|
||||
include $(BUILDDIR)/java/hpi/hpi_common.gmk
|
||||
|
||||
#
|
||||
# Rules for the .so file.
|
||||
#
|
||||
ifeq ($(PLATFORM), solaris)
|
||||
ifneq ($(ARCH), amd64)
|
||||
FILES_reorder += reorder-$(ARCH)
|
||||
endif
|
||||
endif
|
||||
include $(BUILDDIR)/common/Mapfile-vers.gmk
|
||||
include $(BUILDDIR)/common/Library.gmk
|
||||
|
||||
#
|
||||
# HPI flags for native threads.
|
||||
#
|
||||
OTHER_CPPFLAGS += -D_REENTRANT -DNATIVE
|
||||
|
||||
ifeq ($(USE_PTHREADS),true)
|
||||
OTHER_CPPFLAGS += -DUSE_PTHREADS
|
||||
ifeq ($(MOOT_PRIORITIES),true)
|
||||
OTHER_CPPFLAGS += -DMOOT_PRIORITIES
|
||||
endif
|
||||
LIBPOSIX4 = -lposix4
|
||||
OTHER_LDLIBS += -lpthread $(LIBPOSIX4)
|
||||
endif
|
||||
|
||||
HAVE_GETHRVTIME=true
|
||||
ifeq ($(HAVE_GETHRVTIME),true)
|
||||
OTHER_CPPFLAGS += -DHAVE_GETHRVTIME
|
||||
endif
|
||||
|
||||
HAVE_FILIOH=true
|
||||
ifeq ($(HAVE_FILIOH),true)
|
||||
OTHER_CPPFLAGS += -DHAVE_FILIOH
|
||||
endif
|
||||
|
||||
ifeq ($(NO_INTERRUPTIBLE_IO),true)
|
||||
OTHER_CPPFLAGS += -DNO_INTERRUPTIBLE_IO
|
||||
endif
|
||||
|
@ -1,27 +0,0 @@
|
||||
data = R0x2000;
|
||||
text = LOAD ?RXO;
|
||||
# Test Null
|
||||
text: .text%_init;
|
||||
text: .text%checkForCorrectLibthread: OUTPUTDIR/tmp/java/hpi/native_threads/obj/threads_solaris.o;
|
||||
text: .text%init64IO: OUTPUTDIR/tmp/java/hpi/native_threads/obj/system_md.o;
|
||||
text: .text%DLL_Initialize;
|
||||
text: .text%GetInterface: OUTPUTDIR/tmp/java/hpi/native_threads/obj/hpi.o;
|
||||
text: .text%sysBuildLibName;
|
||||
text: .text%sysLoadLibrary;
|
||||
text: .text%sysFindLibraryEntry;
|
||||
text: .text%sysNativePath;
|
||||
text: .text%sysOpen;
|
||||
text: .text%sysSeek;
|
||||
text: .text%lseek64_w;
|
||||
# Test Exit
|
||||
# Test Hello
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%sysAvailable;
|
||||
text: .text%sysFfileMode;
|
||||
text: .text%sysGetLastErrorString;
|
||||
# Test LoadFrame
|
||||
# Test LoadJFrame
|
||||
# Test JHello
|
||||
# SwingSet
|
@ -1,26 +0,0 @@
|
||||
data = R0x2000;
|
||||
text = LOAD ?RXO;
|
||||
# Test Null
|
||||
text: .text%checkForCorrectLibthread: OUTPUTDIR/tmp/java/hpi/native_threads/obj/threads_solaris.o;
|
||||
text: .text%init64IO: OUTPUTDIR/tmp/java/hpi/native_threads/obj/system_md.o;
|
||||
text: .text%DLL_Initialize;
|
||||
text: .text%GetInterface: OUTPUTDIR/tmp/java/hpi/native_threads/obj/hpi.o;
|
||||
text: .text%sysBuildLibName;
|
||||
text: .text%sysLoadLibrary;
|
||||
text: .text%sysFindLibraryEntry;
|
||||
text: .text%sysNativePath;
|
||||
text: .text%sysOpen;
|
||||
text: .text%sysFfileMode;
|
||||
text: .text%sysSeek;
|
||||
text: .text%lseek64_w;
|
||||
text: .text%sysAvailable;
|
||||
# Test Exit
|
||||
# Test Hello
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%sysGetLastErrorString;
|
||||
# Test LoadFrame
|
||||
# Test LoadJFrame
|
||||
# Test JHello
|
||||
# SwingSet
|
@ -1,26 +0,0 @@
|
||||
data = R0x2000;
|
||||
text = LOAD ?RXO;
|
||||
# Test Null
|
||||
text: .text%checkForCorrectLibthread: OUTPUTDIR/tmp/java/hpi/native_threads/obj64/threads_solaris.o;
|
||||
text: .text%init64IO: OUTPUTDIR/tmp/java/hpi/native_threads/obj64/system_md.o;
|
||||
text: .text%DLL_Initialize;
|
||||
text: .text%GetInterface: OUTPUTDIR/tmp/java/hpi/native_threads/obj64/hpi.o;
|
||||
text: .text%sysBuildLibName;
|
||||
text: .text%sysLoadLibrary;
|
||||
text: .text%sysFindLibraryEntry;
|
||||
text: .text%sysNativePath;
|
||||
text: .text%sysOpen;
|
||||
text: .text%sysFfileMode;
|
||||
text: .text%sysSeek;
|
||||
text: .text%lseek64_w;
|
||||
text: .text%sysAvailable;
|
||||
# Test Exit
|
||||
# Test Hello
|
||||
# Test Sleep
|
||||
# Test IntToString
|
||||
# Test LoadToolkit
|
||||
text: .text%sysGetLastErrorString;
|
||||
# Test LoadFrame
|
||||
# Test LoadJFrame
|
||||
# Test JHello
|
||||
# SwingSet
|
@ -1,69 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 1999, 2010, 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.
|
||||
#
|
||||
|
||||
#
|
||||
# Makefile for Windows HPI DLL
|
||||
#
|
||||
BUILDDIR = ../../..
|
||||
MODULE = base
|
||||
LIBRARY = hpi
|
||||
PRODUCT = java
|
||||
THREADDIR = windows_threads
|
||||
LIB_LOCATION = $(BINDIR)
|
||||
|
||||
include $(BUILDDIR)/common/Defs.gmk
|
||||
|
||||
# windows compiler flags
|
||||
ifeq ($(PLATFORM),windows)
|
||||
CPPFLAGS_DBG += -DLOGGING
|
||||
endif
|
||||
|
||||
FILES_c = \
|
||||
linker_md.c \
|
||||
memory_md.c \
|
||||
monitor_md.c \
|
||||
path_md.c \
|
||||
socket_md.c \
|
||||
sys_api_md.c \
|
||||
system_md.c \
|
||||
threads_md.c \
|
||||
hpi.c # trailing blank required!
|
||||
|
||||
JVMLIB =
|
||||
JAVALIB =
|
||||
OTHER_LCF = -export:DLL_Initialize
|
||||
EXTRA_LIBS =
|
||||
|
||||
|
||||
#
|
||||
# Other files/flags shared between the HPIs.
|
||||
#
|
||||
include $(BUILDDIR)/java/hpi/hpi_common.gmk
|
||||
|
||||
#
|
||||
# Rules for the .so file.
|
||||
#
|
||||
include $(BUILDDIR)/common/Library.gmk
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2005, 2011, 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
|
||||
@ -70,14 +70,18 @@ SUNWprivate_1.1 {
|
||||
Java_sun_management_ThreadImpl_dumpThreads0;
|
||||
Java_sun_management_ThreadImpl_findDeadlockedThreads0;
|
||||
Java_sun_management_ThreadImpl_findMonitorDeadlockedThreads0;
|
||||
Java_sun_management_ThreadImpl_getThreadInfo0;
|
||||
Java_sun_management_ThreadImpl_getThreadInfo1;
|
||||
Java_sun_management_ThreadImpl_getThreads;
|
||||
Java_sun_management_ThreadImpl_getThreadTotalCpuTime0;
|
||||
Java_sun_management_ThreadImpl_getThreadTotalCpuTime1;
|
||||
Java_sun_management_ThreadImpl_getThreadUserCpuTime0;
|
||||
Java_sun_management_ThreadImpl_getThreadUserCpuTime1;
|
||||
Java_sun_management_ThreadImpl_getThreadAllocatedMemory1;
|
||||
Java_sun_management_ThreadImpl_resetContentionTimes0;
|
||||
Java_sun_management_ThreadImpl_resetPeakThreadCount0;
|
||||
Java_sun_management_ThreadImpl_setThreadContentionMonitoringEnabled0;
|
||||
Java_sun_management_ThreadImpl_setThreadCpuTimeEnabled0;
|
||||
Java_sun_management_ThreadImpl_setThreadAllocatedMemoryEnabled0;
|
||||
Java_sun_management_VMManagementImpl_getAvailableProcessors;
|
||||
Java_sun_management_VMManagementImpl_getClassInitializationTime;
|
||||
Java_sun_management_VMManagementImpl_getClassLoadingTime;
|
||||
@ -106,6 +110,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_management_VMManagementImpl_initOptionalSupportFields;
|
||||
Java_sun_management_VMManagementImpl_isThreadContentionMonitoringEnabled;
|
||||
Java_sun_management_VMManagementImpl_isThreadCpuTimeEnabled;
|
||||
Java_sun_management_VMManagementImpl_isThreadAllocatedMemoryEnabled;
|
||||
JNI_OnLoad;
|
||||
local:
|
||||
*;
|
||||
|
@ -296,7 +296,7 @@ ifeq ($(PLATFORM), linux)
|
||||
OTHER_LDLIBS += -L$(LIBDIR)/$(LIBARCH) -ljava -lnet -lpthread -ldl
|
||||
endif
|
||||
ifeq ($(PLATFORM), solaris)
|
||||
OTHER_LDLIBS += $(JVMLIB) $(LIBSOCKET) -lposix4 -ldl \
|
||||
OTHER_LDLIBS += $(JVMLIB) $(LIBSOCKET) -lposix4 -ldl -lsendfile \
|
||||
-L$(LIBDIR)/$(LIBARCH) -ljava -lnet
|
||||
endif # PLATFORM
|
||||
|
||||
|
@ -43,7 +43,7 @@ SUBDIRS = \
|
||||
|
||||
# Some demos aren't currently included in OpenJDK
|
||||
ifndef OPENJDK
|
||||
SUBDIRS += Java2D SwingSet2 Stylepad
|
||||
SUBDIRS += Java2D SwingSet2 SwingSet3 Stylepad
|
||||
endif
|
||||
|
||||
include $(BUILDDIR)/common/Subdirs.gmk
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2010, 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
|
||||
@ -24,18 +24,20 @@
|
||||
#
|
||||
|
||||
#
|
||||
# Build HPI (Host Porting Interface) libraries
|
||||
# Makefile to build the SwingSet3 demo.
|
||||
#
|
||||
|
||||
BUILDDIR = ../..
|
||||
BUILDDIR = ../../..
|
||||
PRODUCT = demo/jfc
|
||||
DEMONAME = SwingSet3
|
||||
include $(BUILDDIR)/common/Defs.gmk
|
||||
|
||||
#
|
||||
# Build specified the HPI implementations
|
||||
#
|
||||
SUBDIRS = $(HPIS)
|
||||
include $(BUILDDIR)/common/Subdirs.gmk
|
||||
|
||||
all build clean clobber::
|
||||
$(SUBDIRS-loop)
|
||||
DEMO_ROOT = $(CLOSED_SRC)/share/demo/jfc/$(DEMONAME)
|
||||
DEMO_DESTDIR = $(DEMODIR)/jfc/$(DEMONAME)
|
||||
DEMO_TOPFILES = ./readme.html ./swingset3.png
|
||||
DEMO_SKIP_SRCZIP = true
|
||||
|
||||
#
|
||||
# Demo jar building rules.
|
||||
#
|
||||
include $(BUILDDIR)/common/Demo.gmk
|
@ -369,10 +369,6 @@ FONTCONFIGS_SRC = $(CLOSED_SRC)/solaris/classes/sun/awt/fontconfigs
|
||||
_FONTCONFIGS = \
|
||||
fontconfig.properties \
|
||||
fontconfig.RedHat.properties \
|
||||
fontconfig.RedHat.2.1.properties \
|
||||
fontconfig.RedHat.3.properties \
|
||||
fontconfig.RedHat.4.properties \
|
||||
fontconfig.Sun.properties \
|
||||
fontconfig.Turbo.properties \
|
||||
fontconfig.SuSE.10.properties \
|
||||
fontconfig.SuSE.11.properties
|
||||
@ -388,9 +384,7 @@ ifeq ($(PLATFORM), solaris)
|
||||
|
||||
FONTCONFIGS_SRC = $(PLATFORM_SRC)/classes/sun/awt/fontconfigs
|
||||
_FONTCONFIGS = \
|
||||
fontconfig.properties \
|
||||
fontconfig.5.9.properties \
|
||||
fontconfig.5.8.properties
|
||||
fontconfig.properties
|
||||
|
||||
FONTCONFIGS_SRC_PREFIX = $(PLATFORM).
|
||||
|
||||
|
@ -515,8 +515,7 @@ SUNWprivate_1.1 {
|
||||
getDefaultConfig;
|
||||
Java_sun_font_FontConfigManager_getFontConfig;
|
||||
Java_sun_font_FontConfigManager_getFontConfigAASettings;
|
||||
Java_sun_awt_X11FontManager_getFontPath;
|
||||
Java_sun_awt_X11FontManager_setNativeFontPath;
|
||||
Java_sun_awt_X11FontManager_getFontPathNative;
|
||||
Java_sun_font_SunFontManager_populateFontFileNameMap;
|
||||
|
||||
# CDE private entry point
|
||||
|
@ -537,8 +537,7 @@ SUNWprivate_1.1 {
|
||||
getDefaultConfig;
|
||||
Java_sun_font_FontConfigManager_getFontConfig;
|
||||
Java_sun_font_FontConfigManager_getFontConfigAASettings;
|
||||
Java_sun_awt_X11FontManager_getFontPath;
|
||||
Java_sun_awt_X11FontManager_setNativeFontPath;
|
||||
Java_sun_awt_X11FontManager_getFontPathNative;
|
||||
Java_sun_font_SunFontManager_populateFontFileNameMap;
|
||||
|
||||
# CDE private entry point
|
||||
|
@ -65,7 +65,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_font_FontConfigManager_getFontConfig;
|
||||
Java_sun_font_FontConfigManager_getFontConfigAASettings;
|
||||
Java_sun_font_FontConfigManager_getFontConfigVersion;
|
||||
Java_sun_awt_X11FontManager_getFontPath;
|
||||
Java_sun_awt_X11FontManager_getFontPathNative;
|
||||
|
||||
Java_sun_awt_FontDescriptor_initIDs;
|
||||
Java_sun_awt_PlatformFont_initIDs;
|
||||
|
@ -33,6 +33,7 @@ FILES_java = \
|
||||
sun/net/ProgressEvent.java \
|
||||
sun/net/ProgressListener.java \
|
||||
sun/net/ProgressMeteringPolicy.java \
|
||||
sun/net/SocksProxy.java \
|
||||
sun/net/TelnetInputStream.java \
|
||||
sun/net/TelnetOutputStream.java \
|
||||
sun/net/TelnetProtocolException.java \
|
||||
|
@ -136,8 +136,25 @@ ifeq ($(PLATFORM), linux)
|
||||
-I$(OPENWIN_HOME)/include
|
||||
endif
|
||||
|
||||
# We have some odd logic here because some Solaris 10 updates
|
||||
# have a render.h file that suggests gradients are supported, but
|
||||
# the Xrender.h doesn't have the corresponding type definitions.
|
||||
# Earlier updates have neither. We'd like to know if there's a mismatch.
|
||||
# Whilst in the C preprocessor we can tell if the render.h define's are set
|
||||
# we can't tell anything about C declarations.
|
||||
# A grep of Xrender.h is the only way to know this. If they are absent
|
||||
# we will set a flag indicating this mismatch and the JDK source file
|
||||
# will interpret it to resolve the problem.
|
||||
ifeq ($(PLATFORM), solaris)
|
||||
CPPFLAGS += -I$(OPENWIN_HOME)/include/X11/extensions
|
||||
OS_VERSION := $(shell uname -r)
|
||||
XRENDER_H := $(OPENWIN_HOME)/share/include/X11/extensions/Xrender.h
|
||||
ifeq ($(OS_VERSION),5.10)
|
||||
LINEARGRADIENT_CNT := $(shell $(EGREP) -c XLinearGradient $(XRENDER_H))
|
||||
ifeq ($(LINEARGRADIENT_CNT),0)
|
||||
CFLAGS+= -DSOLARIS10_NO_XRENDER_STRUCTS
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(MILESTONE), internal)
|
||||
|
@ -188,8 +188,7 @@ SUNWprivate_1.1 {
|
||||
Java_sun_font_FontConfigManager_getFontConfig;
|
||||
Java_sun_font_FontConfigManager_getFontConfigAASettings;
|
||||
Java_sun_font_FontConfigManager_getFontConfigVersion;
|
||||
Java_sun_awt_X11FontManager_getFontPath;
|
||||
Java_sun_font_X11FontManager_setNativeFontPath;
|
||||
Java_sun_awt_X11FontManager_getFontPathNative;
|
||||
Java_sun_awt_X11GraphicsEnvironment_initDisplay;
|
||||
Java_sun_awt_X11GraphicsEnvironment_initGLX;
|
||||
Java_sun_awt_X11GraphicsEnvironment_initXRender;
|
||||
|
@ -85,7 +85,6 @@ reorder.jar : $(REORDER_JAR)
|
||||
libs.reorder :
|
||||
ifeq ($(PLATFORM), solaris)
|
||||
$(MAKE) LIBBLDDIR=java/zip LIBTMPDIR=sun/java.util.zip/zip reorder.lib
|
||||
$(MAKE) LIBBLDDIR=java/hpi/native LIBTMPDIR=java/hpi/native_threads reorder.lib
|
||||
$(MAKE) LIBBLDDIR=java/java LIBTMPDIR=java/java.lang/java reorder.lib
|
||||
$(MAKE) LIBBLDDIR=java/nio LIBTMPDIR=java/java.nio/nio reorder.lib
|
||||
$(MAKE) LIBBLDDIR=sun/font LIBTMPDIR=sun/sun.awt.font/fontmanager reorder.lib
|
||||
@ -96,7 +95,6 @@ endif
|
||||
libs.copy:
|
||||
ifeq ($(PLATFORM), solaris)
|
||||
$(CP) $(OUTDIR)/reorder_java_zip-$(ARCH) ../../java/zip/reorder-$(ARCH)
|
||||
$(CP) $(OUTDIR)/reorder_java_hpi_native-$(ARCH) ../../java/hpi/native/reorder-$(ARCH)
|
||||
$(CP) $(OUTDIR)/reorder_java_java-$(ARCH) ../../java/java/reorder-$(ARCH)
|
||||
$(CP) $(OUTDIR)/reorder_sun_font-$(ARCH) ../../sun/font/reorder-$(ARCH)
|
||||
$(CP) $(OUTDIR)/reorder_sun_jpeg-$(ARCH) ../../sun/jpeg/reorder-$(ARCH)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -133,27 +133,60 @@ set_event_notification(jvmtiEventMode mode, EventIndex ei)
|
||||
return error;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int major;
|
||||
int minor;
|
||||
} version_type;
|
||||
|
||||
typedef struct {
|
||||
version_type runtime;
|
||||
version_type compiletime;
|
||||
} compatible_versions_type;
|
||||
|
||||
/*
|
||||
* List of explicitly compatible JVMTI versions, specified as
|
||||
* { runtime version, compile-time version } pairs. -1 is a wildcard.
|
||||
*/
|
||||
static int nof_compatible_versions = 3;
|
||||
static compatible_versions_type compatible_versions_list[] = {
|
||||
/*
|
||||
* FIXUP: Allow version 0 to be compatible with anything
|
||||
* Special check for FCS of 1.0.
|
||||
*/
|
||||
{ { 0, -1 }, { -1, -1 } },
|
||||
{ { -1, -1 }, { 0, -1 } },
|
||||
/*
|
||||
* 1.2 is runtime compatible with 1.1 -- just make sure to check the
|
||||
* version before using any new 1.2 features
|
||||
*/
|
||||
{ { 1, 1 }, { 1, 2 } }
|
||||
};
|
||||
|
||||
|
||||
/* Logic to determine JVMTI version compatibility */
|
||||
static jboolean
|
||||
compatible_versions(jint major_runtime, jint minor_runtime,
|
||||
jint major_compiletime, jint minor_compiletime)
|
||||
{
|
||||
#if 1 /* FIXUP: We allow version 0 to be compatible with anything */
|
||||
/* Special check for FCS of 1.0. */
|
||||
if ( major_runtime == 0 || major_compiletime == 0 ) {
|
||||
return JNI_TRUE;
|
||||
/*
|
||||
* First check to see if versions are explicitly compatible via the
|
||||
* list specified above.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < nof_compatible_versions; ++i) {
|
||||
version_type runtime = compatible_versions_list[i].runtime;
|
||||
version_type comptime = compatible_versions_list[i].compiletime;
|
||||
|
||||
if ((major_runtime == runtime.major || runtime.major == -1) &&
|
||||
(minor_runtime == runtime.minor || runtime.minor == -1) &&
|
||||
(major_compiletime == comptime.major || comptime.major == -1) &&
|
||||
(minor_compiletime == comptime.minor || comptime.minor == -1)) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Runtime major version must match. */
|
||||
if ( major_runtime != major_compiletime ) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
/* Runtime minor version must be >= the version compiled with. */
|
||||
if ( minor_runtime < minor_compiletime ) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
/* Assumed compatible */
|
||||
return JNI_TRUE;
|
||||
|
||||
return major_runtime == major_compiletime &&
|
||||
minor_runtime >= minor_compiletime;
|
||||
}
|
||||
|
||||
/* OnLoad startup:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2010, 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
|
||||
@ -39,6 +39,7 @@
|
||||
#include "stepControl.h"
|
||||
#include "threadControl.h"
|
||||
#include "SDE.h"
|
||||
#include "jvmti.h"
|
||||
|
||||
typedef struct ClassFilter {
|
||||
jclass clazz;
|
||||
@ -275,6 +276,24 @@ patternStringMatch(char *classname, const char *pattern)
|
||||
}
|
||||
}
|
||||
|
||||
static jboolean isVersionGte12x() {
|
||||
jint version;
|
||||
jvmtiError err =
|
||||
JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)(gdata->jvmti, &version);
|
||||
|
||||
if (err == JVMTI_ERROR_NONE) {
|
||||
jint major, minor;
|
||||
|
||||
major = (version & JVMTI_VERSION_MASK_MAJOR)
|
||||
>> JVMTI_VERSION_SHIFT_MAJOR;
|
||||
minor = (version & JVMTI_VERSION_MASK_MINOR)
|
||||
>> JVMTI_VERSION_SHIFT_MINOR;
|
||||
return (major > 1 || major == 1 && minor >= 2);
|
||||
} else {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the object instance in which the event occurred */
|
||||
/* Return NULL if static or if an error occurs */
|
||||
static jobject
|
||||
@ -286,6 +305,14 @@ eventInstance(EventInfo *evinfo)
|
||||
jint modifiers = 0;
|
||||
jvmtiError error;
|
||||
|
||||
static jboolean got_version = JNI_FALSE;
|
||||
static jboolean is_version_gte_12x = JNI_FALSE;
|
||||
|
||||
if (!got_version) {
|
||||
is_version_gte_12x = isVersionGte12x();
|
||||
got_version = JNI_TRUE;
|
||||
}
|
||||
|
||||
switch (evinfo->ei) {
|
||||
case EI_SINGLE_STEP:
|
||||
case EI_BREAKPOINT:
|
||||
@ -314,11 +341,18 @@ eventInstance(EventInfo *evinfo)
|
||||
/* fail if error or static (0x8) */
|
||||
if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) {
|
||||
FrameNumber fnum = 0;
|
||||
/* get slot zero object "this" */
|
||||
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
|
||||
(gdata->jvmti, thread, fnum, 0, &object);
|
||||
if (error != JVMTI_ERROR_NONE)
|
||||
if (is_version_gte_12x) {
|
||||
/* Use new 1.2.x function, GetLocalInstance */
|
||||
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
|
||||
(gdata->jvmti, thread, fnum, &object);
|
||||
} else {
|
||||
/* get slot zero object "this" */
|
||||
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
|
||||
(gdata->jvmti, thread, fnum, 0, &object);
|
||||
}
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
object = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
|
@ -94,15 +94,15 @@ static int numOptions, maxOptions;
|
||||
* Prototypes for functions internal to launcher.
|
||||
*/
|
||||
static void SetClassPath(const char *s);
|
||||
static void SetModulesBootClassPath(const char *s);
|
||||
static void SelectVersion(int argc, char **argv, char **main_class);
|
||||
static jboolean ParseArguments(int *pargc, char ***pargv, char **pjarfile,
|
||||
char **pclassname, int *pret, const char *jvmpath);
|
||||
static jboolean ParseArguments(int *pargc, char ***pargv,
|
||||
int *pmode, char **pwhat,
|
||||
int *pret, const char *jrepath);
|
||||
static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv,
|
||||
InvocationFunctions *ifn);
|
||||
static jstring NewPlatformString(JNIEnv *env, char *s);
|
||||
static jobjectArray NewPlatformStringArray(JNIEnv *env, char **strv, int strc);
|
||||
static jclass LoadMainClass(JNIEnv *env, jboolean isJar, char *name);
|
||||
static jclass LoadMainClass(JNIEnv *env, int mode, char *name);
|
||||
|
||||
static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv);
|
||||
static jboolean AddApplicationOptions(int cpathc, const char **cpathv);
|
||||
@ -158,18 +158,27 @@ static jboolean IsWildCardEnabled();
|
||||
* Running Java code in primordial thread caused many problems. We will
|
||||
* create a new thread to invoke JVM. See 6316197 for more information.
|
||||
*/
|
||||
static jlong threadStackSize = 0; /* stack size of the new thread */
|
||||
static jlong threadStackSize = 0; /* stack size of the new thread */
|
||||
static jlong maxHeapSize = 0; /* max heap size */
|
||||
static jlong initialHeapSize = 0; /* inital heap size */
|
||||
|
||||
int JNICALL JavaMain(void * args); /* entry point */
|
||||
|
||||
enum LaunchMode { // cf. sun.launcher.LauncherHelper
|
||||
LM_UNKNOWN = 0,
|
||||
LM_CLASS,
|
||||
LM_JAR
|
||||
};
|
||||
|
||||
static const char *launchModeNames[]
|
||||
= { "Unknown", "Main class", "JAR file" };
|
||||
|
||||
typedef struct {
|
||||
int argc;
|
||||
char ** argv;
|
||||
char * jarfile;
|
||||
char * classname;
|
||||
InvocationFunctions ifn;
|
||||
int argc;
|
||||
char **argv;
|
||||
int mode;
|
||||
char *what;
|
||||
InvocationFunctions ifn;
|
||||
} JavaMainArgs;
|
||||
|
||||
/*
|
||||
@ -189,8 +198,8 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
|
||||
jint ergo /* ergonomics class policy */
|
||||
)
|
||||
{
|
||||
char *jarfile = 0;
|
||||
char *classname = 0;
|
||||
int mode = LM_UNKNOWN;
|
||||
char *what = NULL;
|
||||
char *cpath = 0;
|
||||
char *main_class = NULL;
|
||||
int ret;
|
||||
@ -277,24 +286,21 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
|
||||
SetClassPath(cpath);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse command line options; if the return value of
|
||||
* ParseArguments is false, the program should exit.
|
||||
/* Parse command line options; if the return value of
|
||||
* ParseArguments is false, the program should exit.
|
||||
*/
|
||||
if (!ParseArguments(&argc, &argv, &jarfile, &classname, &ret, jvmpath)) {
|
||||
if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath))
|
||||
{
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Set bootclasspath for modules */
|
||||
SetModulesBootClassPath(jrepath);
|
||||
|
||||
/* Override class path if -jar flag was specified */
|
||||
if (jarfile != 0) {
|
||||
SetClassPath(jarfile);
|
||||
if (mode == LM_JAR) {
|
||||
SetClassPath(what); /* Override class path */
|
||||
}
|
||||
|
||||
/* set the -Dsun.java.command pseudo property */
|
||||
SetJavaCommandLineProp(classname, jarfile, argc, argv);
|
||||
SetJavaCommandLineProp(what, argc, argv);
|
||||
|
||||
/* Set the -Dsun.java.launcher pseudo property */
|
||||
SetJavaLauncherProp();
|
||||
@ -305,7 +311,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */
|
||||
/* Show the splash screen if needed */
|
||||
ShowSplashScreen();
|
||||
|
||||
return ContinueInNewThread(&ifn, argc, argv, jarfile, classname, ret);
|
||||
return ContinueInNewThread(&ifn, argc, argv, mode, what, ret);
|
||||
|
||||
}
|
||||
/*
|
||||
@ -353,13 +359,13 @@ JavaMain(void * _args)
|
||||
JavaMainArgs *args = (JavaMainArgs *)_args;
|
||||
int argc = args->argc;
|
||||
char **argv = args->argv;
|
||||
char *jarfile = args->jarfile;
|
||||
char *classname = args->classname;
|
||||
int mode = args->mode;
|
||||
char *what = args->what;
|
||||
InvocationFunctions ifn = args->ifn;
|
||||
|
||||
JavaVM *vm = 0;
|
||||
JNIEnv *env = 0;
|
||||
jclass mainClass;
|
||||
jclass mainClass = NULL;
|
||||
jmethodID mainID;
|
||||
jobjectArray mainArgs;
|
||||
int ret = 0;
|
||||
@ -385,7 +391,7 @@ JavaMain(void * _args)
|
||||
CHECK_EXCEPTION_LEAVE(1);
|
||||
}
|
||||
/* If the user specified neither a class name nor a JAR file */
|
||||
if (printXUsage || printUsage || (jarfile == 0 && classname == 0)) {
|
||||
if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) {
|
||||
PrintUsage(env, printXUsage);
|
||||
CHECK_EXCEPTION_LEAVE(1);
|
||||
LEAVE();
|
||||
@ -399,11 +405,11 @@ JavaMain(void * _args)
|
||||
(long)(jint)Counter2Micros(end-start));
|
||||
}
|
||||
|
||||
/* At this stage, argc/argv have the applications' arguments */
|
||||
/* At this stage, argc/argv have the application's arguments */
|
||||
if (JLI_IsTraceLauncher()){
|
||||
int i;
|
||||
printf("Main-Class is '%s'\n", classname ? classname : "");
|
||||
printf("Apps' argc is %d\n", argc);
|
||||
printf("%s is '%s'\n", launchModeNames[mode], what);
|
||||
printf("App's argc is %d\n", argc);
|
||||
for (i=0; i < argc; i++) {
|
||||
printf(" argv[%2d] = '%s'\n", i, argv[i]);
|
||||
}
|
||||
@ -431,11 +437,7 @@ JavaMain(void * _args)
|
||||
* 2) Remove the vestages of maintaining main_class through
|
||||
* the environment (and remove these comments).
|
||||
*/
|
||||
if (jarfile != 0) {
|
||||
mainClass = LoadMainClass(env, JNI_TRUE, jarfile);
|
||||
} else {
|
||||
mainClass = LoadMainClass(env, JNI_FALSE, classname);
|
||||
}
|
||||
mainClass = LoadMainClass(env, mode, what);
|
||||
CHECK_EXCEPTION_NULL_LEAVE(mainClass);
|
||||
|
||||
/*
|
||||
@ -697,7 +699,7 @@ AddOption(char *str, void *info)
|
||||
if (JLI_StrCCmp(str, "-Xms") == 0) {
|
||||
jlong tmp;
|
||||
if (parse_size(str + 4, &tmp)) {
|
||||
initialHeapSize = tmp;
|
||||
initialHeapSize = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -718,44 +720,6 @@ SetClassPath(const char *s)
|
||||
JLI_MemFree((char *) s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the bootclasspath for modules.
|
||||
* A temporary workaround until jigsaw is integrated into JDK 7.
|
||||
*/
|
||||
static void
|
||||
SetModulesBootClassPath(const char *jrepath)
|
||||
{
|
||||
char *def, *s;
|
||||
char pathname[MAXPATHLEN];
|
||||
const char separator[] = { FILE_SEPARATOR, '\0' };
|
||||
const char *orig = jrepath;
|
||||
static const char format[] = "-Xbootclasspath/p:%s";
|
||||
struct stat statbuf;
|
||||
|
||||
/* return if jre/lib/rt.jar exists */
|
||||
JLI_Snprintf(pathname, sizeof(pathname), "%s%slib%srt.jar", jrepath, separator, separator);
|
||||
if (stat(pathname, &statbuf) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* return if jre/classes exists */
|
||||
JLI_Snprintf(pathname, sizeof(pathname), "%s%sclasses", jrepath, separator);
|
||||
if (stat(pathname, &statbuf) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* modularized jre */
|
||||
JLI_Snprintf(pathname, sizeof(pathname), "%s%slib%s*", jrepath, separator, separator);
|
||||
s = (char *) JLI_WildcardExpandClasspath(pathname);
|
||||
def = JLI_MemAlloc(sizeof(format)
|
||||
- 2 /* strlen("%s") */
|
||||
+ JLI_StrLen(s));
|
||||
sprintf(def, format, s);
|
||||
AddOption(def, NULL);
|
||||
if (s != orig)
|
||||
JLI_MemFree((char *) s);
|
||||
}
|
||||
|
||||
/*
|
||||
* The SelectVersion() routine ensures that an appropriate version of
|
||||
* the JRE is running. The specification for the appropriate version
|
||||
@ -1000,16 +964,17 @@ SelectVersion(int argc, char **argv, char **main_class)
|
||||
/*
|
||||
* Parses command line arguments. Returns JNI_FALSE if launcher
|
||||
* should exit without starting vm, returns JNI_TRUE if vm needs
|
||||
* to be started to process given options. *pret (the launcher
|
||||
* to be started to process given options. *pret (the launcher
|
||||
* process return value) is set to 0 for a normal exit.
|
||||
*/
|
||||
static jboolean
|
||||
ParseArguments(int *pargc, char ***pargv, char **pjarfile,
|
||||
char **pclassname, int *pret, const char *jvmpath)
|
||||
ParseArguments(int *pargc, char ***pargv,
|
||||
int *pmode, char **pwhat,
|
||||
int *pret, const char *jrepath)
|
||||
{
|
||||
int argc = *pargc;
|
||||
char **argv = *pargv;
|
||||
jboolean jarflag = JNI_FALSE;
|
||||
int mode = LM_UNKNOWN;
|
||||
char *arg;
|
||||
|
||||
*pret = 0;
|
||||
@ -1019,10 +984,11 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile,
|
||||
if (JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) {
|
||||
ARG_CHECK (argc, ARG_ERROR1, arg);
|
||||
SetClassPath(*argv);
|
||||
mode = LM_CLASS;
|
||||
argv++; --argc;
|
||||
} else if (JLI_StrCmp(arg, "-jar") == 0) {
|
||||
ARG_CHECK (argc, ARG_ERROR2, arg);
|
||||
jarflag = JNI_TRUE;
|
||||
mode = LM_JAR;
|
||||
} else if (JLI_StrCmp(arg, "-help") == 0 ||
|
||||
JLI_StrCmp(arg, "-h") == 0 ||
|
||||
JLI_StrCmp(arg, "-?") == 0) {
|
||||
@ -1102,19 +1068,24 @@ ParseArguments(int *pargc, char ***pargv, char **pjarfile,
|
||||
}
|
||||
|
||||
if (--argc >= 0) {
|
||||
if (jarflag) {
|
||||
*pjarfile = *argv++;
|
||||
*pclassname = NULL;
|
||||
} else {
|
||||
*pjarfile = NULL;
|
||||
*pclassname = *argv++;
|
||||
}
|
||||
*pwhat = *argv++;
|
||||
}
|
||||
|
||||
if (*pwhat == NULL) {
|
||||
*pret = 1;
|
||||
} else if (mode == LM_UNKNOWN) {
|
||||
/* default to LM_CLASS if -jar and -cp option are
|
||||
* not specified */
|
||||
mode = LM_CLASS;
|
||||
}
|
||||
|
||||
if (argc >= 0) {
|
||||
*pargc = argc;
|
||||
*pargv = argv;
|
||||
}
|
||||
if (*pjarfile == NULL && *pclassname == NULL) {
|
||||
*pret = 1;
|
||||
}
|
||||
|
||||
*pmode = mode;
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
@ -1263,7 +1234,7 @@ NewPlatformStringArray(JNIEnv *env, char **strv, int strc)
|
||||
* call it for more details refer to the java implementation.
|
||||
*/
|
||||
static jclass
|
||||
LoadMainClass(JNIEnv *env, jboolean isJar, char *name)
|
||||
LoadMainClass(JNIEnv *env, int mode, char *name)
|
||||
{
|
||||
jclass cls;
|
||||
jmethodID mid;
|
||||
@ -1276,9 +1247,9 @@ LoadMainClass(JNIEnv *env, jboolean isJar, char *name)
|
||||
}
|
||||
NULL_CHECK0(cls = FindBootStrapClass(env, "sun/launcher/LauncherHelper"));
|
||||
NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls, "checkAndLoadMain",
|
||||
"(ZZLjava/lang/String;)Ljava/lang/Object;"));
|
||||
"(ZILjava/lang/String;)Ljava/lang/Class;"));
|
||||
str = (*env)->NewStringUTF(env, name);
|
||||
result = (*env)->CallStaticObjectMethod(env, cls, mid, JNI_TRUE, isJar, str);
|
||||
result = (*env)->CallStaticObjectMethod(env, cls, mid, JNI_TRUE, mode, str);
|
||||
|
||||
if (JLI_IsTraceLauncher()) {
|
||||
end = CounterGet();
|
||||
@ -1424,8 +1395,7 @@ AddApplicationOptions(int cpathc, const char **cpathv)
|
||||
* property is not exported by HotSpot to the Java layer.
|
||||
*/
|
||||
void
|
||||
SetJavaCommandLineProp(char *classname, char *jarfile,
|
||||
int argc, char **argv)
|
||||
SetJavaCommandLineProp(char *what, int argc, char **argv)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
@ -1433,22 +1403,17 @@ SetJavaCommandLineProp(char *classname, char *jarfile,
|
||||
char* javaCommand = NULL;
|
||||
char* dashDstr = "-Dsun.java.command=";
|
||||
|
||||
if (classname == NULL && jarfile == NULL) {
|
||||
if (what == NULL) {
|
||||
/* unexpected, one of these should be set. just return without
|
||||
* setting the property
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* if the class name is not set, then use the jarfile name */
|
||||
if (classname == NULL) {
|
||||
classname = jarfile;
|
||||
}
|
||||
|
||||
/* determine the amount of memory to allocate assuming
|
||||
* the individual components will be space separated
|
||||
*/
|
||||
len = JLI_StrLen(classname);
|
||||
len = JLI_StrLen(what);
|
||||
for (i = 0; i < argc; i++) {
|
||||
len += JLI_StrLen(argv[i]) + 1;
|
||||
}
|
||||
@ -1459,7 +1424,7 @@ SetJavaCommandLineProp(char *classname, char *jarfile,
|
||||
/* build the -D string */
|
||||
*javaCommand = '\0';
|
||||
JLI_StrCat(javaCommand, dashDstr);
|
||||
JLI_StrCat(javaCommand, classname);
|
||||
JLI_StrCat(javaCommand, what);
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
/* the components of the string are space separated. In
|
||||
@ -1479,7 +1444,8 @@ SetJavaCommandLineProp(char *classname, char *jarfile,
|
||||
* JVM would like to know if it's created by a standard Sun launcher, or by
|
||||
* user native application, the following property indicates the former.
|
||||
*/
|
||||
void SetJavaLauncherProp() {
|
||||
void
|
||||
SetJavaLauncherProp() {
|
||||
AddOption("-Dsun.java.launcher=SUN_STANDARD", NULL);
|
||||
}
|
||||
|
||||
@ -1913,8 +1879,8 @@ IsWildCardEnabled()
|
||||
}
|
||||
|
||||
static int
|
||||
ContinueInNewThread(InvocationFunctions* ifn, int argc,
|
||||
char **argv, char *jarfile, char *classname, int ret)
|
||||
ContinueInNewThread(InvocationFunctions* ifn, int argc, char **argv,
|
||||
int mode, char *what, int ret)
|
||||
{
|
||||
|
||||
/*
|
||||
@ -1938,8 +1904,8 @@ ContinueInNewThread(InvocationFunctions* ifn, int argc,
|
||||
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
args.jarfile = jarfile;
|
||||
args.classname = classname;
|
||||
args.mode = mode;
|
||||
args.what = what;
|
||||
args.ifn = *ifn;
|
||||
|
||||
rslt = ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args);
|
||||
|
@ -153,7 +153,7 @@ int ContinueInNewThread0(int (JNICALL *continuation)(void *),
|
||||
|
||||
/* sun.java.launcher.* platform properties. */
|
||||
void SetJavaLauncherPlatformProps(void);
|
||||
void SetJavaCommandLineProp(char* classname, char* jarfile, int argc, char** argv);
|
||||
void SetJavaCommandLineProp(char* what, int argc, char** argv);
|
||||
void SetJavaLauncherProp(void);
|
||||
|
||||
/*
|
||||
@ -178,8 +178,9 @@ jint GetErgoPolicy();
|
||||
|
||||
jboolean ServerClassMachine();
|
||||
|
||||
static int ContinueInNewThread(InvocationFunctions* ifn, int argc, char** argv,
|
||||
char* jarfile, char* classname, int ret);
|
||||
static int ContinueInNewThread(InvocationFunctions* ifn,
|
||||
int argc, char** argv,
|
||||
int mode, char *what, int ret);
|
||||
|
||||
/*
|
||||
* Initialize platform specific settings
|
||||
|
@ -1704,7 +1704,7 @@ class BandStructure {
|
||||
for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
|
||||
assert(attrIndexLimit[i] == 0);
|
||||
attrIndexLimit[i] = 32; // just for the sake of predefs.
|
||||
attrDefs.set(i, new ArrayList<>(Collections.nCopies(
|
||||
attrDefs.set(i, new ArrayList<Attribute.Layout>(Collections.nCopies(
|
||||
attrIndexLimit[i], (Attribute.Layout)null)));
|
||||
|
||||
}
|
||||
|
221
jdk/src/share/classes/com/sun/management/ThreadMXBean.java
Normal file
221
jdk/src/share/classes/com/sun/management/ThreadMXBean.java
Normal file
@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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.
|
||||
*/
|
||||
|
||||
package com.sun.management;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Platform-specific management interface for the thread system
|
||||
* of the Java virtual machine.
|
||||
* <p>
|
||||
* This platform extension is only available to a thread
|
||||
* implementation that supports this extension.
|
||||
*
|
||||
* @author Paul Hohensee
|
||||
* @since 6u25
|
||||
*/
|
||||
|
||||
public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
|
||||
/**
|
||||
* Returns the total CPU time for each thread whose ID is
|
||||
* in the input array {@code ids} in nanoseconds.
|
||||
* The returned values are of nanoseconds precision but
|
||||
* not necessarily nanoseconds accuracy.
|
||||
* <p>
|
||||
* This method is equivalent to calling the
|
||||
* {@link ThreadMXBean#getThreadCpuTime(long)}
|
||||
* method for each thread ID in the input array {@code ids} and setting the
|
||||
* returned value in the corresponding element of the returned array.
|
||||
*
|
||||
* @param ids an array of thread IDs.
|
||||
* @return an array of long values, each of which is the amount of CPU
|
||||
* time the thread whose ID is in the corresponding element of the input
|
||||
* array of IDs has used,
|
||||
* if the thread of a specified ID exists, the thread is alive,
|
||||
* and CPU time measurement is enabled;
|
||||
* {@code -1} otherwise.
|
||||
*
|
||||
* @throws NullPointerException if {@code ids} is {@code null}
|
||||
* @throws IllegalArgumentException if any element in the input array
|
||||
* {@code ids} is {@code <=} {@code 0}.
|
||||
* @throws java.lang.UnsupportedOperationException if the Java
|
||||
* virtual machine implementation does not support CPU time
|
||||
* measurement.
|
||||
*
|
||||
* @see ThreadMXBean#getThreadCpuTime(long)
|
||||
* @see #getThreadUserTime
|
||||
* @see ThreadMXBean#isThreadCpuTimeSupported
|
||||
* @see ThreadMXBean#isThreadCpuTimeEnabled
|
||||
* @see ThreadMXBean#setThreadCpuTimeEnabled
|
||||
*/
|
||||
public long[] getThreadCpuTime(long[] ids);
|
||||
|
||||
/**
|
||||
* Returns the CPU time that each thread whose ID is in the input array
|
||||
* {@code ids} has executed in user mode in nanoseconds.
|
||||
* The returned values are of nanoseconds precision but
|
||||
* not necessarily nanoseconds accuracy.
|
||||
* <p>
|
||||
* This method is equivalent to calling the
|
||||
* {@link ThreadMXBean#getThreadUserTime(long)}
|
||||
* method for each thread ID in the input array {@code ids} and setting the
|
||||
* returned value in the corresponding element of the returned array.
|
||||
*
|
||||
* @param ids an array of thread IDs.
|
||||
* @return an array of long values, each of which is the amount of user
|
||||
* mode CPU time the thread whose ID is in the corresponding element of
|
||||
* the input array of IDs has used,
|
||||
* if the thread of a specified ID exists, the thread is alive,
|
||||
* and CPU time measurement is enabled;
|
||||
* {@code -1} otherwise.
|
||||
*
|
||||
* @throws NullPointerException if {@code ids} is {@code null}
|
||||
* @throws IllegalArgumentException if any element in the input array
|
||||
* {@code ids} is {@code <=} {@code 0}.
|
||||
* @throws java.lang.UnsupportedOperationException if the Java
|
||||
* virtual machine implementation does not support CPU time
|
||||
* measurement.
|
||||
*
|
||||
* @see ThreadMXBean#getThreadUserTime(long)
|
||||
* @see #getThreadCpuTime
|
||||
* @see ThreadMXBean#isThreadCpuTimeSupported
|
||||
* @see ThreadMXBean#isThreadCpuTimeEnabled
|
||||
* @see ThreadMXBean#setThreadCpuTimeEnabled
|
||||
*/
|
||||
public long[] getThreadUserTime(long[] ids);
|
||||
|
||||
/**
|
||||
* Returns an approximation of the total amount of memory, in bytes,
|
||||
* allocated in heap memory for the thread of the specified ID.
|
||||
* The returned value is an approximation because some Java virtual machine
|
||||
* implementations may use object allocation mechanisms that result in a
|
||||
* delay between the time an object is allocated and the time its size is
|
||||
* recorded.
|
||||
* <p>
|
||||
* If the thread of the specified ID is not alive or does not exist,
|
||||
* this method returns {@code -1}. If thread memory allocation measurement
|
||||
* is disabled, this method returns {@code -1}.
|
||||
* A thread is alive if it has been started and has not yet died.
|
||||
* <p>
|
||||
* If thread memory allocation measurement is enabled after the thread has
|
||||
* started, the Java virtual machine implementation may choose any time up
|
||||
* to and including the time that the capability is enabled as the point
|
||||
* where thread memory allocation measurement starts.
|
||||
*
|
||||
* @param id the thread ID of a thread
|
||||
* @return an approximation of the total memory allocated, in bytes, in
|
||||
* heap memory for a thread of the specified ID
|
||||
* if the thread of the specified ID exists, the thread is alive,
|
||||
* and thread memory allocation measurement is enabled;
|
||||
* {@code -1} otherwise.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code id} {@code <=} {@code 0}.
|
||||
* @throws java.lang.UnsupportedOperationException if the Java virtual
|
||||
* machine implementation does not support thread memory allocation
|
||||
* measurement.
|
||||
*
|
||||
* @see #isThreadAllocatedMemorySupported
|
||||
* @see #isThreadAllocatedMemoryEnabled
|
||||
* @see #setThreadAllocatedMemoryEnabled
|
||||
*/
|
||||
public long getThreadAllocatedBytes(long id);
|
||||
|
||||
/**
|
||||
* Returns an approximation of the total amount of memory, in bytes,
|
||||
* allocated in heap memory for each thread whose ID is in the input
|
||||
* array {@code ids}.
|
||||
* The returned values are approximations because some Java virtual machine
|
||||
* implementations may use object allocation mechanisms that result in a
|
||||
* delay between the time an object is allocated and the time its size is
|
||||
* recorded.
|
||||
* <p>
|
||||
* This method is equivalent to calling the
|
||||
* {@link #getThreadAllocatedBytes(long)}
|
||||
* method for each thread ID in the input array {@code ids} and setting the
|
||||
* returned value in the corresponding element of the returned array.
|
||||
*
|
||||
* @param ids an array of thread IDs.
|
||||
* @return an array of long values, each of which is an approximation of
|
||||
* the total memory allocated, in bytes, in heap memory for the thread
|
||||
* whose ID is in the corresponding element of the input array of IDs.
|
||||
*
|
||||
* @throws NullPointerException if {@code ids} is {@code null}
|
||||
* @throws IllegalArgumentException if any element in the input array
|
||||
* {@code ids} is {@code <=} {@code 0}.
|
||||
* @throws java.lang.UnsupportedOperationException if the Java virtual
|
||||
* machine implementation does not support thread memory allocation
|
||||
* measurement.
|
||||
*
|
||||
* @see #getThreadAllocatedBytes(long)
|
||||
* @see #isThreadAllocatedMemorySupported
|
||||
* @see #isThreadAllocatedMemoryEnabled
|
||||
* @see #setThreadAllocatedMemoryEnabled
|
||||
*/
|
||||
public long[] getThreadAllocatedBytes(long[] ids);
|
||||
|
||||
/**
|
||||
* Tests if the Java virtual machine implementation supports thread memory
|
||||
* allocation measurement.
|
||||
*
|
||||
* @return
|
||||
* {@code true}
|
||||
* if the Java virtual machine implementation supports thread memory
|
||||
* allocation measurement;
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isThreadAllocatedMemorySupported();
|
||||
|
||||
/**
|
||||
* Tests if thread memory allocation measurement is enabled.
|
||||
*
|
||||
* @return {@code true} if thread memory allocation measurement is enabled;
|
||||
* {@code false} otherwise.
|
||||
*
|
||||
* @throws java.lang.UnsupportedOperationException if the Java virtual
|
||||
* machine does not support thread memory allocation measurement.
|
||||
*
|
||||
* @see #isThreadAllocatedMemorySupported
|
||||
*/
|
||||
public boolean isThreadAllocatedMemoryEnabled();
|
||||
|
||||
/**
|
||||
* Enables or disables thread memory allocation measurement. The default
|
||||
* is platform dependent.
|
||||
*
|
||||
* @param enable {@code true} to enable;
|
||||
* {@code false} to disable.
|
||||
*
|
||||
* @throws java.lang.UnsupportedOperationException if the Java virtual
|
||||
* machine does not support thread memory allocation measurement.
|
||||
*
|
||||
* @throws java.lang.SecurityException if a security manager
|
||||
* exists and the caller does not have
|
||||
* ManagementPermission("control").
|
||||
*
|
||||
* @see #isThreadAllocatedMemorySupported
|
||||
*/
|
||||
public void setThreadAllocatedMemoryEnabled(boolean enable);
|
||||
}
|
@ -223,7 +223,9 @@ public final class RhinoScriptEngine extends AbstractScriptEngine
|
||||
} catch (RhinoException re) {
|
||||
if (DEBUG) re.printStackTrace();
|
||||
int line = (line = re.lineNumber()) == 0 ? -1 : line;
|
||||
throw new ScriptException(re.toString(), re.sourceName(), line);
|
||||
ScriptException se = new ScriptException(re.toString(), re.sourceName(), line);
|
||||
se.initCause(re);
|
||||
throw se;
|
||||
} finally {
|
||||
cx.exit();
|
||||
}
|
||||
@ -257,6 +259,8 @@ public final class RhinoScriptEngine extends AbstractScriptEngine
|
||||
" str = 'null'; \n" +
|
||||
" } \n" +
|
||||
" var out = context.getWriter(); \n" +
|
||||
" if (!(out instanceof java.io.PrintWriter))\n" +
|
||||
" out = new java.io.PrintWriter(out); \n" +
|
||||
" out.print(String(str)); \n" +
|
||||
" if (newline) out.print('\\n'); \n" +
|
||||
" out.flush(); \n" +
|
||||
|
@ -1180,7 +1180,7 @@ public class PolicyFile extends javax.security.auth.Policy {
|
||||
// Done
|
||||
return certs;
|
||||
|
||||
ArrayList<Certificate> userCertList = new ArrayList<Certificate>();
|
||||
ArrayList<Certificate> userCertList = new ArrayList<>();
|
||||
i = 0;
|
||||
while (i < certs.length) {
|
||||
userCertList.add(certs[i]);
|
||||
|
@ -99,10 +99,10 @@ public class DialogCallbackHandler implements CallbackHandler {
|
||||
throws UnsupportedCallbackException
|
||||
{
|
||||
/* Collect messages to display in the dialog */
|
||||
final List<Object> messages = new ArrayList<Object>(3);
|
||||
final List<Object> messages = new ArrayList<>(3);
|
||||
|
||||
/* Collection actions to perform if the user clicks OK */
|
||||
final List<Action> okActions = new ArrayList<Action>(2);
|
||||
final List<Action> okActions = new ArrayList<>(2);
|
||||
|
||||
ConfirmationInfo confirmation = new ConfirmationInfo();
|
||||
|
||||
|
@ -152,7 +152,7 @@ public class ConfigFile extends javax.security.auth.login.Configuration {
|
||||
|
||||
// new configuration
|
||||
HashMap<String, LinkedList<AppConfigurationEntry>> newConfig =
|
||||
new HashMap<String, LinkedList<AppConfigurationEntry>>();
|
||||
new HashMap<>();
|
||||
|
||||
if (url != null) {
|
||||
|
||||
@ -392,8 +392,7 @@ public class ConfigFile extends javax.security.auth.login.Configuration {
|
||||
String moduleClass;
|
||||
String sflag;
|
||||
AppConfigurationEntry.LoginModuleControlFlag controlFlag;
|
||||
LinkedList<AppConfigurationEntry> configEntries =
|
||||
new LinkedList<AppConfigurationEntry>();
|
||||
LinkedList<AppConfigurationEntry> configEntries = new LinkedList<>();
|
||||
|
||||
// application name
|
||||
appName = st.sval;
|
||||
@ -433,7 +432,7 @@ public class ConfigFile extends javax.security.auth.login.Configuration {
|
||||
}
|
||||
|
||||
// get the args
|
||||
HashMap<String, String> options = new HashMap<String, String>();
|
||||
HashMap<String, String> options = new HashMap<>();
|
||||
String key;
|
||||
String value;
|
||||
while (peek(";") == false) {
|
||||
|
@ -184,7 +184,7 @@ public class JndiLoginModule implements LoginModule {
|
||||
private UnixNumericUserPrincipal UIDPrincipal;
|
||||
private UnixNumericGroupPrincipal GIDPrincipal;
|
||||
private LinkedList<UnixNumericGroupPrincipal> supplementaryGroups =
|
||||
new LinkedList<UnixNumericGroupPrincipal>();
|
||||
new LinkedList<>();
|
||||
|
||||
// initial state
|
||||
private Subject subject;
|
||||
|
@ -658,8 +658,7 @@ public class KeyStoreLoginModule implements LoginModule {
|
||||
throw new FailedLoginException(
|
||||
"Unable to find X.509 certificate chain in keystore");
|
||||
} else {
|
||||
LinkedList<Certificate> certList =
|
||||
new LinkedList<Certificate>();
|
||||
LinkedList<Certificate> certList = new LinkedList<>();
|
||||
for (int i=0; i < fromKeyStore.length; i++) {
|
||||
certList.add(fromKeyStore[i]);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ public class SolarisLoginModule implements LoginModule {
|
||||
private SolarisNumericUserPrincipal UIDPrincipal;
|
||||
private SolarisNumericGroupPrincipal GIDPrincipal;
|
||||
private LinkedList<SolarisNumericGroupPrincipal> supplementaryGroups =
|
||||
new LinkedList<SolarisNumericGroupPrincipal>();
|
||||
new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Initialize this <code>LoginModule</code>.
|
||||
|
@ -70,7 +70,7 @@ public class UnixLoginModule implements LoginModule {
|
||||
private UnixNumericUserPrincipal UIDPrincipal;
|
||||
private UnixNumericGroupPrincipal GIDPrincipal;
|
||||
private LinkedList<UnixNumericGroupPrincipal> supplementaryGroups =
|
||||
new LinkedList<UnixNumericGroupPrincipal>();
|
||||
new LinkedList<>();
|
||||
|
||||
/**
|
||||
* Initialize this <code>LoginModule</code>.
|
||||
|
@ -1387,203 +1387,13 @@ public abstract class CubicCurve2D implements Shape, Cloneable {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Trivially accept if either endpoint is inside the rectangle
|
||||
// (not on its border since it may end there and not go inside)
|
||||
// Record where they lie with respect to the rectangle.
|
||||
// -1 => left, 0 => inside, 1 => right
|
||||
double x1 = getX1();
|
||||
double y1 = getY1();
|
||||
int x1tag = getTag(x1, x, x+w);
|
||||
int y1tag = getTag(y1, y, y+h);
|
||||
if (x1tag == INSIDE && y1tag == INSIDE) {
|
||||
return true;
|
||||
}
|
||||
double x2 = getX2();
|
||||
double y2 = getY2();
|
||||
int x2tag = getTag(x2, x, x+w);
|
||||
int y2tag = getTag(y2, y, y+h);
|
||||
if (x2tag == INSIDE && y2tag == INSIDE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double ctrlx1 = getCtrlX1();
|
||||
double ctrly1 = getCtrlY1();
|
||||
double ctrlx2 = getCtrlX2();
|
||||
double ctrly2 = getCtrlY2();
|
||||
int ctrlx1tag = getTag(ctrlx1, x, x+w);
|
||||
int ctrly1tag = getTag(ctrly1, y, y+h);
|
||||
int ctrlx2tag = getTag(ctrlx2, x, x+w);
|
||||
int ctrly2tag = getTag(ctrly2, y, y+h);
|
||||
|
||||
// Trivially reject if all points are entirely to one side of
|
||||
// the rectangle.
|
||||
if (x1tag < INSIDE && x2tag < INSIDE &&
|
||||
ctrlx1tag < INSIDE && ctrlx2tag < INSIDE)
|
||||
{
|
||||
return false; // All points left
|
||||
}
|
||||
if (y1tag < INSIDE && y2tag < INSIDE &&
|
||||
ctrly1tag < INSIDE && ctrly2tag < INSIDE)
|
||||
{
|
||||
return false; // All points above
|
||||
}
|
||||
if (x1tag > INSIDE && x2tag > INSIDE &&
|
||||
ctrlx1tag > INSIDE && ctrlx2tag > INSIDE)
|
||||
{
|
||||
return false; // All points right
|
||||
}
|
||||
if (y1tag > INSIDE && y2tag > INSIDE &&
|
||||
ctrly1tag > INSIDE && ctrly2tag > INSIDE)
|
||||
{
|
||||
return false; // All points below
|
||||
}
|
||||
|
||||
// Test for endpoints on the edge where either the segment
|
||||
// or the curve is headed "inwards" from them
|
||||
// Note: These tests are a superset of the fast endpoint tests
|
||||
// above and thus repeat those tests, but take more time
|
||||
// and cover more cases
|
||||
if (inwards(x1tag, x2tag, ctrlx1tag) &&
|
||||
inwards(y1tag, y2tag, ctrly1tag))
|
||||
{
|
||||
// First endpoint on border with either edge moving inside
|
||||
return true;
|
||||
}
|
||||
if (inwards(x2tag, x1tag, ctrlx2tag) &&
|
||||
inwards(y2tag, y1tag, ctrly2tag))
|
||||
{
|
||||
// Second endpoint on border with either edge moving inside
|
||||
return true;
|
||||
}
|
||||
|
||||
// Trivially accept if endpoints span directly across the rectangle
|
||||
boolean xoverlap = (x1tag * x2tag <= 0);
|
||||
boolean yoverlap = (y1tag * y2tag <= 0);
|
||||
if (x1tag == INSIDE && x2tag == INSIDE && yoverlap) {
|
||||
return true;
|
||||
}
|
||||
if (y1tag == INSIDE && y2tag == INSIDE && xoverlap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We now know that both endpoints are outside the rectangle
|
||||
// but the 4 points are not all on one side of the rectangle.
|
||||
// Therefore the curve cannot be contained inside the rectangle,
|
||||
// but the rectangle might be contained inside the curve, or
|
||||
// the curve might intersect the boundary of the rectangle.
|
||||
|
||||
double[] eqn = new double[4];
|
||||
double[] res = new double[4];
|
||||
if (!yoverlap) {
|
||||
// Both y coordinates for the closing segment are above or
|
||||
// below the rectangle which means that we can only intersect
|
||||
// if the curve crosses the top (or bottom) of the rectangle
|
||||
// in more than one place and if those crossing locations
|
||||
// span the horizontal range of the rectangle.
|
||||
fillEqn(eqn, (y1tag < INSIDE ? y : y+h), y1, ctrly1, ctrly2, y2);
|
||||
int num = solveCubic(eqn, res);
|
||||
num = evalCubic(res, num, true, true, null,
|
||||
x1, ctrlx1, ctrlx2, x2);
|
||||
// odd counts imply the crossing was out of [0,1] bounds
|
||||
// otherwise there is no way for that part of the curve to
|
||||
// "return" to meet its endpoint
|
||||
return (num == 2 &&
|
||||
getTag(res[0], x, x+w) * getTag(res[1], x, x+w) <= 0);
|
||||
}
|
||||
|
||||
// Y ranges overlap. Now we examine the X ranges
|
||||
if (!xoverlap) {
|
||||
// Both x coordinates for the closing segment are left of
|
||||
// or right of the rectangle which means that we can only
|
||||
// intersect if the curve crosses the left (or right) edge
|
||||
// of the rectangle in more than one place and if those
|
||||
// crossing locations span the vertical range of the rectangle.
|
||||
fillEqn(eqn, (x1tag < INSIDE ? x : x+w), x1, ctrlx1, ctrlx2, x2);
|
||||
int num = solveCubic(eqn, res);
|
||||
num = evalCubic(res, num, true, true, null,
|
||||
y1, ctrly1, ctrly2, y2);
|
||||
// odd counts imply the crossing was out of [0,1] bounds
|
||||
// otherwise there is no way for that part of the curve to
|
||||
// "return" to meet its endpoint
|
||||
return (num == 2 &&
|
||||
getTag(res[0], y, y+h) * getTag(res[1], y, y+h) <= 0);
|
||||
}
|
||||
|
||||
// The X and Y ranges of the endpoints overlap the X and Y
|
||||
// ranges of the rectangle, now find out how the endpoint
|
||||
// line segment intersects the Y range of the rectangle
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double k = y2 * x1 - x2 * y1;
|
||||
int c1tag, c2tag;
|
||||
if (y1tag == INSIDE) {
|
||||
c1tag = x1tag;
|
||||
} else {
|
||||
c1tag = getTag((k + dx * (y1tag < INSIDE ? y : y+h)) / dy, x, x+w);
|
||||
}
|
||||
if (y2tag == INSIDE) {
|
||||
c2tag = x2tag;
|
||||
} else {
|
||||
c2tag = getTag((k + dx * (y2tag < INSIDE ? y : y+h)) / dy, x, x+w);
|
||||
}
|
||||
// If the part of the line segment that intersects the Y range
|
||||
// of the rectangle crosses it horizontally - trivially accept
|
||||
if (c1tag * c2tag <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Now we know that both the X and Y ranges intersect and that
|
||||
// the endpoint line segment does not directly cross the rectangle.
|
||||
//
|
||||
// We can almost treat this case like one of the cases above
|
||||
// where both endpoints are to one side, except that we may
|
||||
// get one or three intersections of the curve with the vertical
|
||||
// side of the rectangle. This is because the endpoint segment
|
||||
// accounts for the other intersection in an even pairing. Thus,
|
||||
// with the endpoint crossing we end up with 2 or 4 total crossings.
|
||||
//
|
||||
// (Remember there is overlap in both the X and Y ranges which
|
||||
// means that the segment itself must cross at least one vertical
|
||||
// edge of the rectangle - in particular, the "near vertical side"
|
||||
// - leaving an odd number of intersections for the curve.)
|
||||
//
|
||||
// Now we calculate the y tags of all the intersections on the
|
||||
// "near vertical side" of the rectangle. We will have one with
|
||||
// the endpoint segment, and one or three with the curve. If
|
||||
// any pair of those vertical intersections overlap the Y range
|
||||
// of the rectangle, we have an intersection. Otherwise, we don't.
|
||||
|
||||
// c1tag = vertical intersection class of the endpoint segment
|
||||
//
|
||||
// Choose the y tag of the endpoint that was not on the same
|
||||
// side of the rectangle as the subsegment calculated above.
|
||||
// Note that we can "steal" the existing Y tag of that endpoint
|
||||
// since it will be provably the same as the vertical intersection.
|
||||
c1tag = ((c1tag * x1tag <= 0) ? y1tag : y2tag);
|
||||
|
||||
// Now we have to calculate an array of solutions of the curve
|
||||
// with the "near vertical side" of the rectangle. Then we
|
||||
// need to sort the tags and do a pairwise range test to see
|
||||
// if either of the pairs of crossings spans the Y range of
|
||||
// the rectangle.
|
||||
//
|
||||
// Note that the c2tag can still tell us which vertical edge
|
||||
// to test against.
|
||||
fillEqn(eqn, (c2tag < INSIDE ? x : x+w), x1, ctrlx1, ctrlx2, x2);
|
||||
int num = solveCubic(eqn, res);
|
||||
num = evalCubic(res, num, true, true, null, y1, ctrly1, ctrly2, y2);
|
||||
|
||||
// Now put all of the tags into a bucket and sort them. There
|
||||
// is an intersection iff one of the pairs of tags "spans" the
|
||||
// Y range of the rectangle.
|
||||
int tags[] = new int[num+1];
|
||||
for (int i = 0; i < num; i++) {
|
||||
tags[i] = getTag(res[i], y, y+h);
|
||||
}
|
||||
tags[num] = c1tag;
|
||||
Arrays.sort(tags);
|
||||
return ((num >= 1 && tags[0] * tags[1] <= 0) ||
|
||||
(num >= 3 && tags[2] * tags[3] <= 0));
|
||||
int numCrossings = rectCrossings(x, y, w, h);
|
||||
// the intended return value is
|
||||
// numCrossings != 0 || numCrossings == Curve.RECT_INTERSECTS
|
||||
// but if (numCrossings != 0) numCrossings == INTERSECTS won't matter
|
||||
// and if !(numCrossings != 0) then numCrossings == 0, so
|
||||
// numCrossings != RECT_INTERSECT
|
||||
return numCrossings != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1602,20 +1412,32 @@ public abstract class CubicCurve2D implements Shape, Cloneable {
|
||||
if (w <= 0 || h <= 0) {
|
||||
return false;
|
||||
}
|
||||
// Assertion: Cubic curves closed by connecting their
|
||||
// endpoints form either one or two convex halves with
|
||||
// the closing line segment as an edge of both sides.
|
||||
if (!(contains(x, y) &&
|
||||
contains(x + w, y) &&
|
||||
contains(x + w, y + h) &&
|
||||
contains(x, y + h))) {
|
||||
return false;
|
||||
|
||||
int numCrossings = rectCrossings(x, y, w, h);
|
||||
return !(numCrossings == 0 || numCrossings == Curve.RECT_INTERSECTS);
|
||||
}
|
||||
|
||||
private int rectCrossings(double x, double y, double w, double h) {
|
||||
int crossings = 0;
|
||||
if (!(getX1() == getX2() && getY1() == getY2())) {
|
||||
crossings = Curve.rectCrossingsForLine(crossings,
|
||||
x, y,
|
||||
x+w, y+h,
|
||||
getX1(), getY1(),
|
||||
getX2(), getY2());
|
||||
if (crossings == Curve.RECT_INTERSECTS) {
|
||||
return crossings;
|
||||
}
|
||||
}
|
||||
// Either the rectangle is entirely inside one of the convex
|
||||
// halves or it crosses from one to the other, in which case
|
||||
// it must intersect the closing line segment.
|
||||
Rectangle2D rect = new Rectangle2D.Double(x, y, w, h);
|
||||
return !rect.intersectsLine(getX1(), getY1(), getX2(), getY2());
|
||||
// we call this with the curve's direction reversed, because we wanted
|
||||
// to call rectCrossingsForLine first, because it's cheaper.
|
||||
return Curve.rectCrossingsForCubic(crossings,
|
||||
x, y,
|
||||
x+w, y+h,
|
||||
getX2(), getY2(),
|
||||
getCtrlX2(), getCtrlY2(),
|
||||
getCtrlX1(), getCtrlY1(),
|
||||
getX1(), getY1(), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -329,7 +329,7 @@ public class ObjectStreamClass implements Serializable {
|
||||
entry = th;
|
||||
}
|
||||
if (future.set(entry)) {
|
||||
Caches.localDescs.put(key, new SoftReference<>(entry));
|
||||
Caches.localDescs.put(key, new SoftReference<Object>(entry));
|
||||
} else {
|
||||
// nested lookup call already set future
|
||||
entry = future.get();
|
||||
@ -2118,7 +2118,7 @@ public class ObjectStreamClass implements Serializable {
|
||||
entry = th;
|
||||
}
|
||||
future.set(entry);
|
||||
Caches.reflectors.put(key, new SoftReference<>(entry));
|
||||
Caches.reflectors.put(key, new SoftReference<Object>(entry));
|
||||
}
|
||||
|
||||
if (entry instanceof FieldReflector) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2011, 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
|
||||
@ -27,7 +27,9 @@ package java.io;
|
||||
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
|
||||
/**
|
||||
* A <code>PrintStream</code> adds functionality to another output stream,
|
||||
@ -56,7 +58,7 @@ public class PrintStream extends FilterOutputStream
|
||||
implements Appendable, Closeable
|
||||
{
|
||||
|
||||
private boolean autoFlush = false;
|
||||
private final boolean autoFlush;
|
||||
private boolean trouble = false;
|
||||
private Formatter formatter;
|
||||
|
||||
@ -67,6 +69,60 @@ public class PrintStream extends FilterOutputStream
|
||||
private BufferedWriter textOut;
|
||||
private OutputStreamWriter charOut;
|
||||
|
||||
/**
|
||||
* nonNull is explicitly declared here so as not to create an extra
|
||||
* dependency on java.util.Objects.nonNull. PrintStream is loaded
|
||||
* early during system initialization.
|
||||
*/
|
||||
private static <T> T nonNull(T obj, String message) {
|
||||
if (obj == null)
|
||||
throw new NullPointerException(message);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a charset object for the given charset name.
|
||||
* @throws NullPointerException is csn is null
|
||||
* @throws UnsupportedEncodingException if the charset is not supported
|
||||
*/
|
||||
private static Charset toCharset(String csn)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
nonNull(csn, "charsetName");
|
||||
try {
|
||||
return Charset.forName(csn);
|
||||
} catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
|
||||
// UnsupportedEncodingException should be thrown
|
||||
throw new UnsupportedEncodingException(csn);
|
||||
}
|
||||
}
|
||||
|
||||
/* Private constructors */
|
||||
private PrintStream(boolean autoFlush, OutputStream out) {
|
||||
super(out);
|
||||
this.autoFlush = autoFlush;
|
||||
this.charOut = new OutputStreamWriter(this);
|
||||
this.textOut = new BufferedWriter(charOut);
|
||||
}
|
||||
|
||||
private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
|
||||
super(out);
|
||||
this.autoFlush = autoFlush;
|
||||
this.charOut = new OutputStreamWriter(this, charset);
|
||||
this.textOut = new BufferedWriter(charOut);
|
||||
}
|
||||
|
||||
/* Variant of the private constructor so that the given charset name
|
||||
* can be verified before evaluating the OutputStream argument. Used
|
||||
* by constructors creating a FileOutputStream that also take a
|
||||
* charset name.
|
||||
*/
|
||||
private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
this(autoFlush, out, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new print stream. This stream will not flush automatically.
|
||||
*
|
||||
@ -79,27 +135,6 @@ public class PrintStream extends FilterOutputStream
|
||||
this(out, false);
|
||||
}
|
||||
|
||||
/* Initialization is factored into a private constructor (note the swapped
|
||||
* parameters so that this one isn't confused with the public one) and a
|
||||
* separate init method so that the following two public constructors can
|
||||
* share code. We use a separate init method so that the constructor that
|
||||
* takes an encoding will throw an NPE for a null stream before it throws
|
||||
* an UnsupportedEncodingException for an unsupported encoding.
|
||||
*/
|
||||
|
||||
private PrintStream(boolean autoFlush, OutputStream out)
|
||||
{
|
||||
super(out);
|
||||
if (out == null)
|
||||
throw new NullPointerException("Null output stream");
|
||||
this.autoFlush = autoFlush;
|
||||
}
|
||||
|
||||
private void init(OutputStreamWriter osw) {
|
||||
this.charOut = osw;
|
||||
this.textOut = new BufferedWriter(osw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new print stream.
|
||||
*
|
||||
@ -113,8 +148,7 @@ public class PrintStream extends FilterOutputStream
|
||||
* @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
|
||||
*/
|
||||
public PrintStream(OutputStream out, boolean autoFlush) {
|
||||
this(autoFlush, out);
|
||||
init(new OutputStreamWriter(this));
|
||||
this(autoFlush, nonNull(out, "Null output stream"));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,8 +172,9 @@ public class PrintStream extends FilterOutputStream
|
||||
public PrintStream(OutputStream out, boolean autoFlush, String encoding)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
this(autoFlush, out);
|
||||
init(new OutputStreamWriter(this, encoding));
|
||||
this(autoFlush,
|
||||
nonNull(out, "Null output stream"),
|
||||
toCharset(encoding));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,7 +206,6 @@ public class PrintStream extends FilterOutputStream
|
||||
*/
|
||||
public PrintStream(String fileName) throws FileNotFoundException {
|
||||
this(false, new FileOutputStream(fileName));
|
||||
init(new OutputStreamWriter(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -210,8 +244,8 @@ public class PrintStream extends FilterOutputStream
|
||||
public PrintStream(String fileName, String csn)
|
||||
throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
this(false, new FileOutputStream(fileName));
|
||||
init(new OutputStreamWriter(this, csn));
|
||||
// ensure charset is checked before the file is opened
|
||||
this(false, toCharset(csn), new FileOutputStream(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,7 +277,6 @@ public class PrintStream extends FilterOutputStream
|
||||
*/
|
||||
public PrintStream(File file) throws FileNotFoundException {
|
||||
this(false, new FileOutputStream(file));
|
||||
init(new OutputStreamWriter(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,8 +315,8 @@ public class PrintStream extends FilterOutputStream
|
||||
public PrintStream(File file, String csn)
|
||||
throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
this(false, new FileOutputStream(file));
|
||||
init(new OutputStreamWriter(this, csn));
|
||||
// ensure charset is checked before the file is opened
|
||||
this(false, toCharset(csn), new FileOutputStream(file));
|
||||
}
|
||||
|
||||
/** Check to make sure that the stream has not been closed */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2011, 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
|
||||
@ -25,8 +25,12 @@
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
|
||||
/**
|
||||
* Prints formatted representations of objects to a text-output stream. This
|
||||
@ -59,7 +63,7 @@ public class PrintWriter extends Writer {
|
||||
*/
|
||||
protected Writer out;
|
||||
|
||||
private boolean autoFlush = false;
|
||||
private final boolean autoFlush;
|
||||
private boolean trouble = false;
|
||||
private Formatter formatter;
|
||||
private PrintStream psOut = null;
|
||||
@ -68,7 +72,24 @@ public class PrintWriter extends Writer {
|
||||
* Line separator string. This is the value of the line.separator
|
||||
* property at the moment that the stream was created.
|
||||
*/
|
||||
private String lineSeparator;
|
||||
private final String lineSeparator;
|
||||
|
||||
/**
|
||||
* Returns a charset object for the given charset name.
|
||||
* @throws NullPointerException is csn is null
|
||||
* @throws UnsupportedEncodingException if the charset is not supported
|
||||
*/
|
||||
private static Charset toCharset(String csn)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
Objects.nonNull(csn, "charsetName");
|
||||
try {
|
||||
return Charset.forName(csn);
|
||||
} catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
|
||||
// UnsupportedEncodingException should be thrown
|
||||
throw new UnsupportedEncodingException(csn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new PrintWriter, without automatic line flushing.
|
||||
@ -164,6 +185,14 @@ public class PrintWriter extends Writer {
|
||||
false);
|
||||
}
|
||||
|
||||
/* Private constructor */
|
||||
private PrintWriter(Charset charset, File file)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new PrintWriter, without automatic line flushing, with the
|
||||
* specified file name and charset. This convenience constructor creates
|
||||
@ -200,8 +229,7 @@ public class PrintWriter extends Writer {
|
||||
public PrintWriter(String fileName, String csn)
|
||||
throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), csn)),
|
||||
false);
|
||||
this(toCharset(csn), new File(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,8 +300,7 @@ public class PrintWriter extends Writer {
|
||||
public PrintWriter(File file, String csn)
|
||||
throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), csn)),
|
||||
false);
|
||||
this(toCharset(csn), file);
|
||||
}
|
||||
|
||||
/** Checks to make sure that the stream has not been closed */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2009, 2011, 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
|
||||
@ -33,7 +33,7 @@ package java.lang;
|
||||
*/
|
||||
public interface AutoCloseable {
|
||||
/**
|
||||
* Close this resource, relinquishing any underlying resources.
|
||||
* Closes this resource, relinquishing any underlying resources.
|
||||
* This method is invoked automatically by the {@code
|
||||
* try}-with-resources statement.
|
||||
*
|
||||
@ -48,6 +48,10 @@ public interface AutoCloseable {
|
||||
* visible side effect, unlike {@code Closeable.close} which is
|
||||
* required to have no effect if called more than once.
|
||||
*
|
||||
* However, while not required to be idempotent, implementers of
|
||||
* this interface are strongly encouraged to make their {@code
|
||||
* close} methods idempotent.
|
||||
*
|
||||
* @throws Exception if this resource cannot be closed
|
||||
*/
|
||||
void close() throws Exception;
|
||||
|
@ -67,7 +67,7 @@ class StringCoding {
|
||||
}
|
||||
|
||||
private static <T> void set(ThreadLocal<SoftReference<T>> tl, T ob) {
|
||||
tl.set(new SoftReference<>(ob));
|
||||
tl.set(new SoftReference<T>(ob));
|
||||
}
|
||||
|
||||
// Trim the given byte array to the given length
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2011, 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
|
||||
@ -809,7 +809,7 @@ public class Throwable implements Serializable {
|
||||
native StackTraceElement getStackTraceElement(int index);
|
||||
|
||||
/**
|
||||
* Read a {@code Throwable} from a stream, enforcing
|
||||
* Reads a {@code Throwable} from a stream, enforcing
|
||||
* well-formedness constraints on fields. Null entries and
|
||||
* self-pointers are not allowed in the list of {@code
|
||||
* suppressedExceptions}. Null entries are not allowed for stack
|
||||
@ -865,9 +865,10 @@ public class Throwable implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified exception to the list of exceptions that
|
||||
* were suppressed, typically by the {@code try}-with-resources
|
||||
* statement, in order to deliver this exception.
|
||||
* Appends the specified exception to the exceptions that were
|
||||
* suppressed in order to deliver this exception. This method is
|
||||
* typically called (automatically and implicitly) by the {@code
|
||||
* try}-with-resources statement.
|
||||
*
|
||||
* If the first exception to be suppressed is {@code null}, that
|
||||
* indicates suppressed exception information will <em>not</em> be
|
||||
|
@ -677,8 +677,7 @@ class InetAddress implements java.io.Serializable {
|
||||
|
||||
static InetAddressImpl impl;
|
||||
|
||||
private static HashMap<String, InetAddress[]> lookupTable
|
||||
= new HashMap<String, InetAddress[]>();
|
||||
private static final HashMap<String, Void> lookupTable = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Represents a cache entry
|
||||
@ -737,7 +736,7 @@ class InetAddress implements java.io.Serializable {
|
||||
|
||||
// As we iterate in insertion order we can
|
||||
// terminate when a non-expired entry is found.
|
||||
LinkedList<String> expired = new LinkedList<String>();
|
||||
LinkedList<String> expired = new LinkedList<>();
|
||||
long now = System.currentTimeMillis();
|
||||
for (String key : cache.keySet()) {
|
||||
CacheEntry entry = cache.get(key);
|
||||
@ -1227,43 +1226,45 @@ class InetAddress implements java.io.Serializable {
|
||||
// lookupTable and return null so the
|
||||
// following code would do a lookup itself.
|
||||
if ((addresses = checkLookupTable(host)) == null) {
|
||||
// This is the first thread which looks up the addresses
|
||||
// this host or the cache entry for this host has been
|
||||
// expired so this thread should do the lookup.
|
||||
for (NameService nameService : nameServices) {
|
||||
try {
|
||||
/*
|
||||
* Do not put the call to lookup() inside the
|
||||
* constructor. if you do you will still be
|
||||
* allocating space when the lookup fails.
|
||||
*/
|
||||
try {
|
||||
// This is the first thread which looks up the addresses
|
||||
// this host or the cache entry for this host has been
|
||||
// expired so this thread should do the lookup.
|
||||
for (NameService nameService : nameServices) {
|
||||
try {
|
||||
/*
|
||||
* Do not put the call to lookup() inside the
|
||||
* constructor. if you do you will still be
|
||||
* allocating space when the lookup fails.
|
||||
*/
|
||||
|
||||
addresses = nameService.lookupAllHostAddr(host);
|
||||
success = true;
|
||||
break;
|
||||
} catch (UnknownHostException uhe) {
|
||||
if (host.equalsIgnoreCase("localhost")) {
|
||||
InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
|
||||
addresses = local;
|
||||
addresses = nameService.lookupAllHostAddr(host);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
addresses = unknown_array;
|
||||
success = false;
|
||||
ex = uhe;
|
||||
} catch (UnknownHostException uhe) {
|
||||
if (host.equalsIgnoreCase("localhost")) {
|
||||
InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
|
||||
addresses = local;
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
addresses = unknown_array;
|
||||
success = false;
|
||||
ex = uhe;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the addresses.
|
||||
cacheAddresses(host, addresses, success);
|
||||
// Delete the host from the lookupTable, and
|
||||
// notify all threads waiting for the monitor
|
||||
// for lookupTable.
|
||||
updateLookupTable(host);
|
||||
if (!success && ex != null)
|
||||
throw ex;
|
||||
// Cache the addresses.
|
||||
cacheAddresses(host, addresses, success);
|
||||
if (!success && ex != null)
|
||||
throw ex;
|
||||
} finally {
|
||||
// Delete host from the lookupTable and notify
|
||||
// all threads waiting on the lookupTable monitor.
|
||||
updateLookupTable(host);
|
||||
}
|
||||
}
|
||||
|
||||
return addresses;
|
||||
@ -1271,16 +1272,13 @@ class InetAddress implements java.io.Serializable {
|
||||
|
||||
|
||||
private static InetAddress[] checkLookupTable(String host) {
|
||||
// make sure addresses is null.
|
||||
InetAddress[] addresses = null;
|
||||
|
||||
synchronized (lookupTable) {
|
||||
// If the host isn't in the lookupTable, add it in the
|
||||
// lookuptable and return null. The caller should do
|
||||
// the lookup.
|
||||
if (lookupTable.containsKey(host) == false) {
|
||||
lookupTable.put(host, null);
|
||||
return addresses;
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the host is in the lookupTable, it means that another
|
||||
@ -1298,10 +1296,11 @@ class InetAddress implements java.io.Serializable {
|
||||
// the host. This thread should retry to get the addresses
|
||||
// from the addressCache. If it doesn't get the addresses from
|
||||
// the cache, it will try to look up the addresses itself.
|
||||
addresses = getCachedAddresses(host);
|
||||
InetAddress[] addresses = getCachedAddresses(host);
|
||||
if (addresses == null) {
|
||||
synchronized (lookupTable) {
|
||||
lookupTable.put(host, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,55 +493,44 @@ public final class NetworkInterface {
|
||||
* @see java.net.InetAddress#getAddress()
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if ((obj == null) || !(obj instanceof NetworkInterface)) {
|
||||
if (!(obj instanceof NetworkInterface)) {
|
||||
return false;
|
||||
}
|
||||
NetworkInterface netIF = (NetworkInterface)obj;
|
||||
if (name != null ) {
|
||||
if (netIF.getName() != null) {
|
||||
if (!name.equals(netIF.getName())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
NetworkInterface that = (NetworkInterface)obj;
|
||||
if (this.name != null ) {
|
||||
if (!this.name.equals(that.name)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (netIF.getName() != null) {
|
||||
if (that.name != null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Enumeration newAddrs = netIF.getInetAddresses();
|
||||
int i = 0;
|
||||
for (i = 0; newAddrs.hasMoreElements();newAddrs.nextElement(), i++);
|
||||
if (addrs == null) {
|
||||
if (i != 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Compare number of addresses (in the checked subset)
|
||||
*/
|
||||
int count = 0;
|
||||
Enumeration e = getInetAddresses();
|
||||
for (; e.hasMoreElements(); count++) {
|
||||
e.nextElement();
|
||||
}
|
||||
if (i != count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.addrs == null) {
|
||||
return that.addrs == null;
|
||||
} else if (that.addrs == null) {
|
||||
return false;
|
||||
}
|
||||
newAddrs = netIF.getInetAddresses();
|
||||
for (; newAddrs.hasMoreElements();) {
|
||||
boolean equal = false;
|
||||
Enumeration thisAddrs = getInetAddresses();
|
||||
InetAddress newAddr = (InetAddress)newAddrs.nextElement();
|
||||
for (; thisAddrs.hasMoreElements();) {
|
||||
InetAddress thisAddr = (InetAddress)thisAddrs.nextElement();
|
||||
if (thisAddr.equals(newAddr)) {
|
||||
equal = true;
|
||||
|
||||
/* Both addrs not null. Compare number of addresses */
|
||||
|
||||
if (this.addrs.length != that.addrs.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InetAddress[] thatAddrs = that.addrs;
|
||||
int count = thatAddrs.length;
|
||||
|
||||
for (int i=0; i<count; i++) {
|
||||
boolean found = false;
|
||||
for (int j=0; j<count; j++) {
|
||||
if (addrs[i].equals(thatAddrs[j])) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!equal) {
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -549,12 +538,7 @@ public final class NetworkInterface {
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int count = name == null? 0: name.hashCode();
|
||||
Enumeration<InetAddress> addrs = getInetAddresses();
|
||||
while (addrs.hasMoreElements()) {
|
||||
count += addrs.nextElement().hashCode();
|
||||
}
|
||||
return count;
|
||||
return name == null? 0: name.hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2011, 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
|
||||
@ -29,6 +29,7 @@ import java.io.OutputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import sun.net.SocksProxy;
|
||||
import sun.net.www.ParseUtil;
|
||||
/* import org.ietf.jgss.*; */
|
||||
|
||||
@ -397,6 +398,11 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
// Use getHostString() to avoid reverse lookups
|
||||
server = ((InetSocketAddress) p.address()).getHostString();
|
||||
serverPort = ((InetSocketAddress) p.address()).getPort();
|
||||
if (p instanceof SocksProxy) {
|
||||
if (((SocksProxy)p).protocolVersion() == 4) {
|
||||
useV4 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Connects to the SOCKS server
|
||||
try {
|
||||
@ -700,6 +706,11 @@ class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
|
||||
// Use getHostString() to avoid reverse lookups
|
||||
server = ((InetSocketAddress) p.address()).getHostString();
|
||||
serverPort = ((InetSocketAddress) p.address()).getPort();
|
||||
if (p instanceof SocksProxy) {
|
||||
if (((SocksProxy)p).protocolVersion() == 4) {
|
||||
useV4 = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Connects to the SOCKS server
|
||||
try {
|
||||
|
@ -27,19 +27,15 @@ package java.net;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.io.File;
|
||||
import java.io.FilePermission;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Closeable;
|
||||
import java.lang.ref.*;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.*;
|
||||
import java.util.jar.Manifest;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Attributes.Name;
|
||||
import java.security.CodeSigner;
|
||||
@ -194,6 +190,65 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
acc = AccessController.getContext();
|
||||
}
|
||||
|
||||
/* A map (used as a set) to keep track of closeable local resources
|
||||
* (either JarFiles or FileInputStreams). We don't care about
|
||||
* Http resources since they don't need to be closed.
|
||||
*
|
||||
* If the resource is coming from a jar file
|
||||
* we keep a (weak) reference to the JarFile object which can
|
||||
* be closed if URLClassLoader.close() called. Due to jar file
|
||||
* caching there will typically be only one JarFile object
|
||||
* per underlying jar file.
|
||||
*
|
||||
* For file resources, which is probably a less common situation
|
||||
* we have to keep a weak reference to each stream.
|
||||
*/
|
||||
|
||||
private WeakHashMap<Closeable,Void>
|
||||
closeables = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Returns an input stream for reading the specified resource.
|
||||
* If this loader is closed, then any resources opened by this method
|
||||
* will be closed.
|
||||
*
|
||||
* <p> The search order is described in the documentation for {@link
|
||||
* #getResource(String)}. </p>
|
||||
*
|
||||
* @param name
|
||||
* The resource name
|
||||
*
|
||||
* @return An input stream for reading the resource, or <tt>null</tt>
|
||||
* if the resource could not be found
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
public InputStream getResourceAsStream(String name) {
|
||||
URL url = getResource(name);
|
||||
try {
|
||||
if (url == null) {
|
||||
return null;
|
||||
}
|
||||
URLConnection urlc = url.openConnection();
|
||||
InputStream is = urlc.getInputStream();
|
||||
if (urlc instanceof JarURLConnection) {
|
||||
JarURLConnection juc = (JarURLConnection)urlc;
|
||||
JarFile jar = juc.getJarFile();
|
||||
synchronized (closeables) {
|
||||
if (!closeables.containsKey(jar)) {
|
||||
closeables.put(jar, null);
|
||||
}
|
||||
}
|
||||
} else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
|
||||
synchronized (closeables) {
|
||||
closeables.put(is, null);
|
||||
}
|
||||
}
|
||||
return is;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this URLClassLoader, so that it can no longer be used to load
|
||||
@ -202,8 +257,8 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
* delegation hierarchy are still accessible. Also, any classes or resources
|
||||
* that are already loaded, are still accessible.
|
||||
* <p>
|
||||
* In the case of jar: and file: URLs, it also closes any class files,
|
||||
* or JAR files that were opened by it. If another thread is loading a
|
||||
* In the case of jar: and file: URLs, it also closes any files
|
||||
* that were opened by it. If another thread is loading a
|
||||
* class when the {@code close} method is invoked, then the result of
|
||||
* that load is undefined.
|
||||
* <p>
|
||||
@ -213,10 +268,10 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
* loader has no effect.
|
||||
* <p>
|
||||
* @throws IOException if closing any file opened by this class loader
|
||||
* resulted in an IOException. Any such exceptions are caught, and a
|
||||
* single IOException is thrown after the last file has been closed.
|
||||
* If only one exception was thrown, it will be set as the <i>cause</i>
|
||||
* of this IOException.
|
||||
* resulted in an IOException. Any such exceptions are caught internally.
|
||||
* If only one is caught, then it is re-thrown. If more than one exception
|
||||
* is caught, then the second and following exceptions are added
|
||||
* as suppressed exceptions of the first one caught, which is then re-thrown.
|
||||
*
|
||||
* @throws SecurityException if a security manager is set, and it denies
|
||||
* {@link RuntimePermission}<tt>("closeClassLoader")</tt>
|
||||
@ -229,21 +284,33 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
|
||||
security.checkPermission(new RuntimePermission("closeClassLoader"));
|
||||
}
|
||||
List<IOException> errors = ucp.closeLoaders();
|
||||
|
||||
// now close any remaining streams.
|
||||
|
||||
synchronized (closeables) {
|
||||
Set<Closeable> keys = closeables.keySet();
|
||||
for (Closeable c : keys) {
|
||||
try {
|
||||
c.close();
|
||||
} catch (IOException ioex) {
|
||||
errors.add(ioex);
|
||||
}
|
||||
}
|
||||
closeables.clear();
|
||||
}
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (errors.size() == 1) {
|
||||
throw new IOException (
|
||||
"Error closing URLClassLoader resource",
|
||||
errors.get(0)
|
||||
);
|
||||
}
|
||||
// Several exceptions. So, just combine the error messages
|
||||
String errormsg = "Error closing resources: ";
|
||||
|
||||
IOException firstex = errors.remove(0);
|
||||
|
||||
// Suppress any remaining exceptions
|
||||
|
||||
for (IOException error: errors) {
|
||||
errormsg = errormsg + "[" + error.toString() + "] ";
|
||||
firstex.addSuppressed(error);
|
||||
}
|
||||
throw new IOException (errormsg);
|
||||
throw firstex;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,10 +127,15 @@ of proxies.</P>
|
||||
are specified. If SOCKS is supported by a Java SE implementation, the
|
||||
following properties will be used:</P>
|
||||
<UL>
|
||||
<LI><P><B>socksProxyHost</B> (default: <non>)<BR>
|
||||
<LI><P><B>socksProxyHost</B> (default: <none>)<BR>
|
||||
The hostname, or address, of the proxy server.</P>
|
||||
<LI><P><B>socksProxyPort</B> (default: 1080)<BR>
|
||||
The port number of the proxy server.</P>
|
||||
<LI><P><B>socksProxyVersion</B> (default: 5)<BR>
|
||||
The version of the SOCKS protocol supported by the server. The
|
||||
default is <code>5</code> indicating SOCKS V5, alternatively
|
||||
<code>4</code> can be specified for SOCKS V4. Setting the property
|
||||
to values other than these leads to unspecified behavior.</P>
|
||||
<LI><P><B>java.net.socks.username</B> (default: <none>)<BR>
|
||||
Username to use if the SOCKSv5 server asks for authentication
|
||||
and no java.net.Authenticator instance was found.</P>
|
||||
|
@ -121,7 +121,7 @@ public final class AccessControlContext {
|
||||
this.context = null;
|
||||
}
|
||||
} else {
|
||||
List<ProtectionDomain> v = new ArrayList<ProtectionDomain>(context.length);
|
||||
List<ProtectionDomain> v = new ArrayList<>(context.length);
|
||||
for (int i =0; i< context.length; i++) {
|
||||
if ((context[i] != null) && (!v.contains(context[i])))
|
||||
v.add(context[i]);
|
||||
|
@ -515,7 +515,7 @@ implements java.io.Serializable
|
||||
|
||||
// Copy perms into a Hashtable
|
||||
Hashtable<String, Permission> permissions =
|
||||
new Hashtable<String, Permission>(perms.size()*2);
|
||||
new Hashtable<>(perms.size()*2);
|
||||
|
||||
synchronized (this) {
|
||||
permissions.putAll(perms);
|
||||
|
@ -188,7 +188,7 @@ public class CodeSource implements java.io.Serializable {
|
||||
} else if (signers != null) {
|
||||
// Convert the code signers to certs
|
||||
ArrayList<java.security.cert.Certificate> certChains =
|
||||
new ArrayList<java.security.cert.Certificate>();
|
||||
new ArrayList<>();
|
||||
for (int i = 0; i < signers.length; i++) {
|
||||
certChains.addAll(
|
||||
signers[i].getSignerCertPath().getCertificates());
|
||||
@ -606,10 +606,10 @@ public class CodeSource implements java.io.Serializable {
|
||||
|
||||
// Iterate through all the certificates
|
||||
int i = 0;
|
||||
List<CodeSigner> signers = new ArrayList<CodeSigner>();
|
||||
List<CodeSigner> signers = new ArrayList<>();
|
||||
while (i < certs.length) {
|
||||
List<java.security.cert.Certificate> certChain =
|
||||
new ArrayList<java.security.cert.Certificate>();
|
||||
new ArrayList<>();
|
||||
certChain.add(certs[i++]); // first cert is an end-entity cert
|
||||
int j = i;
|
||||
|
||||
|
@ -362,7 +362,7 @@ implements Serializable
|
||||
|
||||
// Copy perms into a Hashtable
|
||||
Hashtable<Class<?>, PermissionCollection> perms =
|
||||
new Hashtable<Class<?>, PermissionCollection>(permsMap.size()*2); // no sync; estimate
|
||||
new Hashtable<>(permsMap.size()*2); // no sync; estimate
|
||||
synchronized (this) {
|
||||
perms.putAll(permsMap);
|
||||
}
|
||||
@ -567,7 +567,7 @@ implements Serializable
|
||||
|
||||
// Copy perms into a Hashtable
|
||||
Hashtable<Permission, Permission> perms =
|
||||
new Hashtable<Permission, Permission>(permsMap.size()*2);
|
||||
new Hashtable<>(permsMap.size()*2);
|
||||
synchronized (this) {
|
||||
perms.putAll(permsMap);
|
||||
}
|
||||
|
@ -336,8 +336,8 @@ public class ProtectionDomain {
|
||||
int swag = 32;
|
||||
int vcap = 8;
|
||||
Enumeration<Permission> e;
|
||||
List<Permission> pdVector = new ArrayList<Permission>(vcap);
|
||||
List<Permission> plVector = new ArrayList<Permission>(swag);
|
||||
List<Permission> pdVector = new ArrayList<>(vcap);
|
||||
List<Permission> plVector = new ArrayList<>(swag);
|
||||
|
||||
//
|
||||
// Build a vector of domain permissions for subsequent merge
|
||||
|
@ -437,7 +437,7 @@ public abstract class Provider extends Properties {
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
Map<Object,Object> copy = new HashMap<Object,Object>();
|
||||
Map<Object,Object> copy = new HashMap<>();
|
||||
for (Map.Entry<Object,Object> entry : super.entrySet()) {
|
||||
copy.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
@ -719,7 +719,7 @@ public abstract class Provider extends Properties {
|
||||
}
|
||||
if (serviceSet == null) {
|
||||
ensureLegacyParsed();
|
||||
Set<Service> set = new LinkedHashSet<Service>();
|
||||
Set<Service> set = new LinkedHashSet<>();
|
||||
if (serviceMap != null) {
|
||||
set.addAll(serviceMap.values());
|
||||
}
|
||||
@ -1395,7 +1395,7 @@ public abstract class Provider extends Properties {
|
||||
if (s != null) {
|
||||
String[] classNames = s.split("\\|");
|
||||
List<Class> classList =
|
||||
new ArrayList<Class>(classNames.length);
|
||||
new ArrayList<>(classNames.length);
|
||||
for (String className : classNames) {
|
||||
Class clazz = getKeyClass(className);
|
||||
if (clazz != null) {
|
||||
|
@ -50,7 +50,7 @@ public class SecureClassLoader extends ClassLoader {
|
||||
// HashMap that maps CodeSource to ProtectionDomain
|
||||
// @GuardedBy("pdcache")
|
||||
private final HashMap<CodeSource, ProtectionDomain> pdcache =
|
||||
new HashMap<CodeSource, ProtectionDomain>(11);
|
||||
new HashMap<>(11);
|
||||
|
||||
private static final Debug debug = Debug.getInstance("scl");
|
||||
|
||||
|
@ -545,8 +545,7 @@ public final class Security {
|
||||
value = filter.substring(index + 1);
|
||||
}
|
||||
|
||||
Hashtable<String, String> hashtableFilter =
|
||||
new Hashtable<String, String>(1);
|
||||
Hashtable<String, String> hashtableFilter = new Hashtable<>(1);
|
||||
hashtableFilter.put(key, value);
|
||||
|
||||
return (getProviders(hashtableFilter));
|
||||
@ -606,7 +605,7 @@ public final class Security {
|
||||
// Then only return those providers who satisfy the selection criteria.
|
||||
Provider[] allProviders = Security.getProviders();
|
||||
Set<String> keySet = filter.keySet();
|
||||
LinkedHashSet<Provider> candidates = new LinkedHashSet<Provider>(5);
|
||||
LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
|
||||
|
||||
// Returns all installed providers
|
||||
// if the selection criteria is null.
|
||||
@ -660,8 +659,7 @@ public final class Security {
|
||||
}
|
||||
|
||||
// Map containing cached Spi Class objects of the specified type
|
||||
private static final Map<String,Class> spiMap =
|
||||
new ConcurrentHashMap<String,Class>();
|
||||
private static final Map<String, Class> spiMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Return the Class object for the given engine type
|
||||
@ -885,7 +883,7 @@ public final class Security {
|
||||
String attrName,
|
||||
String filterValue,
|
||||
Provider[] allProviders) {
|
||||
LinkedHashSet<Provider> candidates = new LinkedHashSet<Provider>(5);
|
||||
LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
|
||||
for (int i = 0; i < allProviders.length; i++) {
|
||||
if (isCriterionSatisfied(allProviders[i], serviceName,
|
||||
algName,
|
||||
@ -1082,7 +1080,7 @@ public final class Security {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
HashSet<String> result = new HashSet<String>();
|
||||
HashSet<String> result = new HashSet<>();
|
||||
Provider[] providers = Security.getProviders();
|
||||
|
||||
for (int i = 0; i < providers.length; i++) {
|
||||
|
@ -198,7 +198,7 @@ implements java.io.Serializable
|
||||
if (this.certs == null) {
|
||||
// extract the signer certs
|
||||
ArrayList<java.security.cert.Certificate> signerCerts =
|
||||
new ArrayList<java.security.cert.Certificate>();
|
||||
new ArrayList<>();
|
||||
i = 0;
|
||||
while (i < certs.length) {
|
||||
signerCerts.add(certs[i]);
|
||||
|
@ -119,7 +119,7 @@ implements java.io.Serializable
|
||||
|
||||
public Enumeration<Permission> elements() {
|
||||
List<Permission> results =
|
||||
new ArrayList<Permission>(); // where results are stored
|
||||
new ArrayList<>(); // where results are stored
|
||||
|
||||
// Get iterator of Map values (which are lists of permissions)
|
||||
synchronized (this) {
|
||||
@ -161,7 +161,7 @@ implements java.io.Serializable
|
||||
|
||||
// Copy perms into a Hashtable
|
||||
Hashtable<String, Vector<UnresolvedPermission>> permissions =
|
||||
new Hashtable<String, Vector<UnresolvedPermission>>(perms.size()*2);
|
||||
new Hashtable<>(perms.size()*2);
|
||||
|
||||
// Convert each entry (List) into a Vector
|
||||
synchronized (this) {
|
||||
@ -169,8 +169,7 @@ implements java.io.Serializable
|
||||
for (Map.Entry<String, List<UnresolvedPermission>> e : set) {
|
||||
// Convert list into Vector
|
||||
List<UnresolvedPermission> list = e.getValue();
|
||||
Vector<UnresolvedPermission> vec =
|
||||
new Vector<UnresolvedPermission>(list.size());
|
||||
Vector<UnresolvedPermission> vec = new Vector<>(list.size());
|
||||
synchronized (list) {
|
||||
vec.addAll(list);
|
||||
}
|
||||
@ -207,8 +206,7 @@ implements java.io.Serializable
|
||||
for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
|
||||
// Convert Vector into ArrayList
|
||||
Vector<UnresolvedPermission> vec = e.getValue();
|
||||
List<UnresolvedPermission> list =
|
||||
new ArrayList<UnresolvedPermission>(vec.size());
|
||||
List<UnresolvedPermission> list = new ArrayList<>(vec.size());
|
||||
list.addAll(vec);
|
||||
|
||||
// Add to Hashtable being serialized
|
||||
|
@ -473,7 +473,9 @@ public class Timestamp extends java.util.Date {
|
||||
* @since 1.4
|
||||
*/
|
||||
public int compareTo(Timestamp ts) {
|
||||
int i = super.compareTo(ts);
|
||||
long thisTime = this.getTime();
|
||||
long anotherTime = ts.getTime();
|
||||
int i = (thisTime<anotherTime ? -1 :(thisTime==anotherTime?0 :1));
|
||||
if (i == 0) {
|
||||
if (nanos > ts.nanos) {
|
||||
return 1;
|
||||
|
@ -1452,10 +1452,10 @@ public class Collections {
|
||||
* when o is a Map.Entry, and calls o.setValue.
|
||||
*/
|
||||
public boolean containsAll(Collection<?> coll) {
|
||||
Iterator<?> it = coll.iterator();
|
||||
while (it.hasNext())
|
||||
if (!contains(it.next())) // Invokes safe contains() above
|
||||
for (Object e : coll) {
|
||||
if (!contains(e)) // Invokes safe contains() above
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean equals(Object o) {
|
||||
@ -3713,45 +3713,91 @@ public class Collections {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if the two specified collections have no
|
||||
* Returns {@code true} if the two specified collections have no
|
||||
* elements in common.
|
||||
*
|
||||
* <p>Care must be exercised if this method is used on collections that
|
||||
* do not comply with the general contract for <tt>Collection</tt>.
|
||||
* do not comply with the general contract for {@code Collection}.
|
||||
* Implementations may elect to iterate over either collection and test
|
||||
* for containment in the other collection (or to perform any equivalent
|
||||
* computation). If either collection uses a nonstandard equality test
|
||||
* (as does a {@link SortedSet} whose ordering is not <i>compatible with
|
||||
* equals</i>, or the key set of an {@link IdentityHashMap}), both
|
||||
* (as does a {@link SortedSet} whose ordering is not <em>compatible with
|
||||
* equals</em>, or the key set of an {@link IdentityHashMap}), both
|
||||
* collections must use the same nonstandard equality test, or the
|
||||
* result of this method is undefined.
|
||||
*
|
||||
* <p>Care must also be exercised when using collections that have
|
||||
* restrictions on the elements that they may contain. Collection
|
||||
* implementations are allowed to throw exceptions for any operation
|
||||
* involving elements they deem ineligible. For absolute safety the
|
||||
* specified collections should contain only elements which are
|
||||
* eligible elements for both collections.
|
||||
*
|
||||
* <p>Note that it is permissible to pass the same collection in both
|
||||
* parameters, in which case the method will return true if and only if
|
||||
* the collection is empty.
|
||||
* parameters, in which case the method will return {@code true} if and
|
||||
* only if the collection is empty.
|
||||
*
|
||||
* @param c1 a collection
|
||||
* @param c2 a collection
|
||||
* @throws NullPointerException if either collection is null
|
||||
* @return {@code true} if the two specified collections have no
|
||||
* elements in common.
|
||||
* @throws NullPointerException if either collection is {@code null}.
|
||||
* @throws NullPointerException if one collection contains a {@code null}
|
||||
* element and {@code null} is not an eligible element for the other collection.
|
||||
* (optional)
|
||||
* @throws ClassCastException if one collection contains an element that is
|
||||
* of a type which is ineligible for the other collection. (optional)
|
||||
* @since 1.5
|
||||
*/
|
||||
public static boolean disjoint(Collection<?> c1, Collection<?> c2) {
|
||||
/*
|
||||
* We're going to iterate through c1 and test for inclusion in c2.
|
||||
* If c1 is a Set and c2 isn't, swap the collections. Otherwise,
|
||||
* place the shorter collection in c1. Hopefully this heuristic
|
||||
* will minimize the cost of the operation.
|
||||
*/
|
||||
if ((c1 instanceof Set) && !(c2 instanceof Set) ||
|
||||
(c1.size() > c2.size())) {
|
||||
Collection<?> tmp = c1;
|
||||
c1 = c2;
|
||||
c2 = tmp;
|
||||
// The collection to be used for contains(). Preference is given to
|
||||
// the collection who's contains() has lower O() complexity.
|
||||
Collection<?> contains = c2;
|
||||
// The collection to be iterated. If the collections' contains() impl
|
||||
// are of different O() complexity, the collection with slower
|
||||
// contains() will be used for iteration. For collections who's
|
||||
// contains() are of the same complexity then best performance is
|
||||
// achieved by iterating the smaller collection.
|
||||
Collection<?> iterate = c1;
|
||||
|
||||
// Performance optimization cases. The heuristics:
|
||||
// 1. Generally iterate over c1.
|
||||
// 2. If c1 is a Set then iterate over c2.
|
||||
// 3. If either collection is empty then result is always true.
|
||||
// 4. Iterate over the smaller Collection.
|
||||
if (c1 instanceof Set) {
|
||||
// Use c1 for contains as a Set's contains() is expected to perform
|
||||
// better than O(N/2)
|
||||
iterate = c2;
|
||||
contains = c1;
|
||||
} else if (!(c2 instanceof Set)) {
|
||||
// Both are mere Collections. Iterate over smaller collection.
|
||||
// Example: If c1 contains 3 elements and c2 contains 50 elements and
|
||||
// assuming contains() requires ceiling(N/2) comparisons then
|
||||
// checking for all c1 elements in c2 would require 75 comparisons
|
||||
// (3 * ceiling(50/2)) vs. checking all c2 elements in c1 requiring
|
||||
// 100 comparisons (50 * ceiling(3/2)).
|
||||
int c1size = c1.size();
|
||||
int c2size = c2.size();
|
||||
if (c1size == 0 || c2size == 0) {
|
||||
// At least one collection is empty. Nothing will match.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c1size > c2size) {
|
||||
iterate = c2;
|
||||
contains = c1;
|
||||
}
|
||||
}
|
||||
|
||||
for (Object e : c1)
|
||||
if (c2.contains(e))
|
||||
for (Object e : iterate) {
|
||||
if (contains.contains(e)) {
|
||||
// Found a common element. Collections are not disjoint.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// No common elements were found.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, 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
|
||||
@ -41,6 +41,8 @@ import java.math.BigInteger;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.IllegalCharsetNameException;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
@ -1838,22 +1840,53 @@ import sun.misc.FormattedFloatingDecimal;
|
||||
*/
|
||||
public final class Formatter implements Closeable, Flushable {
|
||||
private Appendable a;
|
||||
private Locale l;
|
||||
private final Locale l;
|
||||
|
||||
private IOException lastException;
|
||||
|
||||
private char zero = '0';
|
||||
private final char zero;
|
||||
private static double scaleUp;
|
||||
|
||||
// 1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
|
||||
// + 3 (max # exp digits) + 4 (error) = 30
|
||||
private static final int MAX_FD_CHARS = 30;
|
||||
|
||||
// Initialize internal data.
|
||||
private void init(Appendable a, Locale l) {
|
||||
/**
|
||||
* Returns a charset object for the given charset name.
|
||||
* @throws NullPointerException is csn is null
|
||||
* @throws UnsupportedEncodingException if the charset is not supported
|
||||
*/
|
||||
private static Charset toCharset(String csn)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
Objects.nonNull(csn, "charsetName");
|
||||
try {
|
||||
return Charset.forName(csn);
|
||||
} catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
|
||||
// UnsupportedEncodingException should be thrown
|
||||
throw new UnsupportedEncodingException(csn);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Appendable nonNullAppendable(Appendable a) {
|
||||
if (a == null)
|
||||
return new StringBuilder();
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Private constructors */
|
||||
private Formatter(Locale l, Appendable a) {
|
||||
this.a = a;
|
||||
this.l = l;
|
||||
setZero();
|
||||
this.zero = getZero(l);
|
||||
}
|
||||
|
||||
private Formatter(Charset charset, Locale l, File file)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
this(l,
|
||||
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1867,7 +1900,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* virtual machine.
|
||||
*/
|
||||
public Formatter() {
|
||||
init(new StringBuilder(), Locale.getDefault(Locale.Category.FORMAT));
|
||||
this(Locale.getDefault(Locale.Category.FORMAT), new StringBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1881,9 +1914,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* {@code null} then a {@link StringBuilder} will be created.
|
||||
*/
|
||||
public Formatter(Appendable a) {
|
||||
if (a == null)
|
||||
a = new StringBuilder();
|
||||
init(a, Locale.getDefault(Locale.Category.FORMAT));
|
||||
this(Locale.getDefault(Locale.Category.FORMAT), nonNullAppendable(a));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1900,7 +1931,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* is applied.
|
||||
*/
|
||||
public Formatter(Locale l) {
|
||||
init(new StringBuilder(), l);
|
||||
this(l, new StringBuilder());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1916,9 +1947,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* is applied.
|
||||
*/
|
||||
public Formatter(Appendable a, Locale l) {
|
||||
if (a == null)
|
||||
a = new StringBuilder();
|
||||
init(a, l);
|
||||
this(l, nonNullAppendable(a));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1949,8 +1978,8 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* creating the file
|
||||
*/
|
||||
public Formatter(String fileName) throws FileNotFoundException {
|
||||
init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
|
||||
Locale.getDefault(Locale.Category.FORMAT));
|
||||
this(Locale.getDefault(Locale.Category.FORMAT),
|
||||
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2025,8 +2054,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
public Formatter(String fileName, String csn, Locale l)
|
||||
throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), csn)),
|
||||
l);
|
||||
this(toCharset(csn), l, new File(fileName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2057,8 +2085,8 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* creating the file
|
||||
*/
|
||||
public Formatter(File file) throws FileNotFoundException {
|
||||
init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
|
||||
Locale.getDefault(Locale.Category.FORMAT));
|
||||
this(Locale.getDefault(Locale.Category.FORMAT),
|
||||
new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2133,8 +2161,7 @@ public final class Formatter implements Closeable, Flushable {
|
||||
public Formatter(File file, String csn, Locale l)
|
||||
throws FileNotFoundException, UnsupportedEncodingException
|
||||
{
|
||||
init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), csn)),
|
||||
l);
|
||||
this(toCharset(csn), l, file);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2151,9 +2178,8 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* The stream to use as the destination of this formatter.
|
||||
*/
|
||||
public Formatter(PrintStream ps) {
|
||||
if (ps == null)
|
||||
throw new NullPointerException();
|
||||
init((Appendable)ps, Locale.getDefault(Locale.Category.FORMAT));
|
||||
this(Locale.getDefault(Locale.Category.FORMAT),
|
||||
(Appendable)Objects.nonNull(ps));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2171,8 +2197,8 @@ public final class Formatter implements Closeable, Flushable {
|
||||
* The output will be buffered.
|
||||
*/
|
||||
public Formatter(OutputStream os) {
|
||||
init(new BufferedWriter(new OutputStreamWriter(os)),
|
||||
Locale.getDefault(Locale.Category.FORMAT));
|
||||
this(Locale.getDefault(Locale.Category.FORMAT),
|
||||
new BufferedWriter(new OutputStreamWriter(os)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2222,13 +2248,15 @@ public final class Formatter implements Closeable, Flushable {
|
||||
public Formatter(OutputStream os, String csn, Locale l)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
init(new BufferedWriter(new OutputStreamWriter(os, csn)), l);
|
||||
this(l, new BufferedWriter(new OutputStreamWriter(os, csn)));
|
||||
}
|
||||
|
||||
private void setZero() {
|
||||
private static char getZero(Locale l) {
|
||||
if ((l != null) && !l.equals(Locale.US)) {
|
||||
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
|
||||
zero = dfs.getZeroDigit();
|
||||
return dfs.getZeroDigit();
|
||||
} else {
|
||||
return '0';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,9 +26,9 @@
|
||||
package java.util;
|
||||
|
||||
/**
|
||||
* Linked list implementation of the {@link List} and {@link Deque} interfaces.
|
||||
* Implements all optional operations, and permits all elements (including
|
||||
* {@code null}).
|
||||
* Doubly-linked list implementation of the {@code List} and {@code Deque}
|
||||
* interfaces. Implements all optional list operations, and permits all
|
||||
* elements (including {@code null}).
|
||||
*
|
||||
* <p>All of the operations perform as could be expected for a doubly-linked
|
||||
* list. Operations that index into the list will traverse the list from
|
||||
@ -249,7 +249,7 @@ public class LinkedList<E>
|
||||
* @return the last element in this list
|
||||
* @throws NoSuchElementException if this list is empty
|
||||
*/
|
||||
public E getLast() {
|
||||
public E getLast() {
|
||||
final Node<E> l = last;
|
||||
if (l == null)
|
||||
throw new NoSuchElementException();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, 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
|
||||
@ -571,10 +571,8 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* @return A scanner with the specified source and pattern
|
||||
*/
|
||||
private Scanner(Readable source, Pattern pattern) {
|
||||
if (source == null)
|
||||
throw new NullPointerException("source");
|
||||
if (pattern == null)
|
||||
throw new NullPointerException("pattern");
|
||||
assert source != null : "source should not be null";
|
||||
assert pattern != null : "pattern should not be null";
|
||||
this.source = source;
|
||||
delimPattern = pattern;
|
||||
buf = CharBuffer.allocate(BUFFER_SIZE);
|
||||
@ -593,7 +591,7 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* interface
|
||||
*/
|
||||
public Scanner(Readable source) {
|
||||
this(source, WHITESPACE_PATTERN);
|
||||
this(Objects.nonNull(source, "source"), WHITESPACE_PATTERN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -620,23 +618,27 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* does not exist
|
||||
*/
|
||||
public Scanner(InputStream source, String charsetName) {
|
||||
this(makeReadable(source, charsetName), WHITESPACE_PATTERN);
|
||||
this(makeReadable(Objects.nonNull(source, "source"), toCharset(charsetName)),
|
||||
WHITESPACE_PATTERN);
|
||||
}
|
||||
|
||||
private static Readable makeReadable(InputStream source,
|
||||
String charsetName)
|
||||
{
|
||||
if (source == null)
|
||||
throw new NullPointerException("source");
|
||||
InputStreamReader isr = null;
|
||||
/**
|
||||
* Returns a charset object for the given charset name.
|
||||
* @throws NullPointerException is csn is null
|
||||
* @throws IllegalArgumentException if the charset is not supported
|
||||
*/
|
||||
private static Charset toCharset(String csn) {
|
||||
Objects.nonNull(csn, "charsetName");
|
||||
try {
|
||||
isr = new InputStreamReader(source, charsetName);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
IllegalArgumentException iae = new IllegalArgumentException();
|
||||
iae.initCause(uee);
|
||||
throw iae;
|
||||
return Charset.forName(csn);
|
||||
} catch (IllegalCharsetNameException|UnsupportedCharsetException e) {
|
||||
// IllegalArgumentException should be thrown
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
return isr;
|
||||
}
|
||||
|
||||
private static Readable makeReadable(InputStream source, Charset charset) {
|
||||
return new InputStreamReader(source, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -648,9 +650,7 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* @param source A file to be scanned
|
||||
* @throws FileNotFoundException if source is not found
|
||||
*/
|
||||
public Scanner(File source)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
public Scanner(File source) throws FileNotFoundException {
|
||||
this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
|
||||
}
|
||||
|
||||
@ -669,8 +669,27 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
public Scanner(File source, String charsetName)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
this((ReadableByteChannel)(new FileInputStream(source).getChannel()),
|
||||
charsetName);
|
||||
this(Objects.nonNull(source), toDecoder(charsetName));
|
||||
}
|
||||
|
||||
private Scanner(File source, CharsetDecoder dec)
|
||||
throws FileNotFoundException
|
||||
{
|
||||
this(makeReadable((ReadableByteChannel)(new FileInputStream(source).getChannel()), dec));
|
||||
}
|
||||
|
||||
private static CharsetDecoder toDecoder(String charsetName) {
|
||||
Objects.nonNull(charsetName, "charsetName");
|
||||
try {
|
||||
return Charset.forName(charsetName).newDecoder();
|
||||
} catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
|
||||
throw new IllegalArgumentException(charsetName);
|
||||
}
|
||||
}
|
||||
|
||||
private static Readable makeReadable(ReadableByteChannel source,
|
||||
CharsetDecoder dec) {
|
||||
return Channels.newReader(source, dec, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -708,10 +727,12 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* if the specified encoding is not found
|
||||
* @since 1.7
|
||||
*/
|
||||
public Scanner(FileRef source, String charsetName)
|
||||
throws IOException
|
||||
{
|
||||
this(source.newInputStream(), charsetName);
|
||||
public Scanner(FileRef source, String charsetName) throws IOException {
|
||||
this(Objects.nonNull(source), toCharset(charsetName));
|
||||
}
|
||||
|
||||
private Scanner(FileRef source, Charset charset) throws IOException {
|
||||
this(makeReadable(source.newInputStream(), charset));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -733,16 +754,12 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* @param source A channel to scan
|
||||
*/
|
||||
public Scanner(ReadableByteChannel source) {
|
||||
this(makeReadable(source), WHITESPACE_PATTERN);
|
||||
this(makeReadable(Objects.nonNull(source, "source")),
|
||||
WHITESPACE_PATTERN);
|
||||
}
|
||||
|
||||
private static Readable makeReadable(ReadableByteChannel source) {
|
||||
if (source == null)
|
||||
throw new NullPointerException("source");
|
||||
String defaultCharsetName =
|
||||
java.nio.charset.Charset.defaultCharset().name();
|
||||
return Channels.newReader(source,
|
||||
java.nio.charset.Charset.defaultCharset().name());
|
||||
return makeReadable(source, Charset.defaultCharset().newDecoder());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -757,17 +774,8 @@ public final class Scanner implements Iterator<String>, Closeable {
|
||||
* does not exist
|
||||
*/
|
||||
public Scanner(ReadableByteChannel source, String charsetName) {
|
||||
this(makeReadable(source, charsetName), WHITESPACE_PATTERN);
|
||||
}
|
||||
|
||||
private static Readable makeReadable(ReadableByteChannel source,
|
||||
String charsetName)
|
||||
{
|
||||
if (source == null)
|
||||
throw new NullPointerException("source");
|
||||
if (!Charset.isSupported(charsetName))
|
||||
throw new IllegalArgumentException(charsetName);
|
||||
return Channels.newReader(source, charsetName);
|
||||
this(makeReadable(Objects.nonNull(source, "source"), toDecoder(charsetName)),
|
||||
WHITESPACE_PATTERN);
|
||||
}
|
||||
|
||||
// Private primitives used to support scanning
|
||||
|
@ -49,14 +49,14 @@ import java.util.*;
|
||||
* <p>This is a classic "bounded buffer", in which a
|
||||
* fixed-sized array holds elements inserted by producers and
|
||||
* extracted by consumers. Once created, the capacity cannot be
|
||||
* increased. Attempts to <tt>put</tt> an element into a full queue
|
||||
* will result in the operation blocking; attempts to <tt>take</tt> an
|
||||
* changed. Attempts to {@code put} an element into a full queue
|
||||
* will result in the operation blocking; attempts to {@code take} an
|
||||
* element from an empty queue will similarly block.
|
||||
*
|
||||
* <p> This class supports an optional fairness policy for ordering
|
||||
* <p>This class supports an optional fairness policy for ordering
|
||||
* waiting producer and consumer threads. By default, this ordering
|
||||
* is not guaranteed. However, a queue constructed with fairness set
|
||||
* to <tt>true</tt> grants threads access in FIFO order. Fairness
|
||||
* to {@code true} grants threads access in FIFO order. Fairness
|
||||
* generally decreases throughput but reduces variability and avoids
|
||||
* starvation.
|
||||
*
|
||||
@ -83,14 +83,17 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
private static final long serialVersionUID = -817911632652898426L;
|
||||
|
||||
/** The queued items */
|
||||
private final E[] items;
|
||||
/** items index for next take, poll or remove */
|
||||
private int takeIndex;
|
||||
/** items index for next put, offer, or add. */
|
||||
private int putIndex;
|
||||
/** Number of items in the queue */
|
||||
private int count;
|
||||
/** The queued items */
|
||||
final Object[] items;
|
||||
|
||||
/** items index for next take, poll, peek or remove */
|
||||
int takeIndex;
|
||||
|
||||
/** items index for next put, offer, or add */
|
||||
int putIndex;
|
||||
|
||||
/** Number of elements in the queue */
|
||||
int count;
|
||||
|
||||
/*
|
||||
* Concurrency control uses the classic two-condition algorithm
|
||||
@ -98,7 +101,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
|
||||
/** Main lock guarding all access */
|
||||
private final ReentrantLock lock;
|
||||
final ReentrantLock lock;
|
||||
/** Condition for waiting takes */
|
||||
private final Condition notEmpty;
|
||||
/** Condition for waiting puts */
|
||||
@ -110,7 +113,36 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* Circularly increment i.
|
||||
*/
|
||||
final int inc(int i) {
|
||||
return (++i == items.length)? 0 : i;
|
||||
return (++i == items.length) ? 0 : i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Circularly decrement i.
|
||||
*/
|
||||
final int dec(int i) {
|
||||
return ((i == 0) ? items.length : i) - 1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> E cast(Object item) {
|
||||
return (E) item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns item at index i.
|
||||
*/
|
||||
final E itemAt(int i) {
|
||||
return this.<E>cast(items[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws NullPointerException if argument is null.
|
||||
*
|
||||
* @param v the element
|
||||
*/
|
||||
private static void checkNotNull(Object v) {
|
||||
if (v == null)
|
||||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,8 +161,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* Call only when holding lock.
|
||||
*/
|
||||
private E extract() {
|
||||
final E[] items = this.items;
|
||||
E x = items[takeIndex];
|
||||
final Object[] items = this.items;
|
||||
E x = this.<E>cast(items[takeIndex]);
|
||||
items[takeIndex] = null;
|
||||
takeIndex = inc(takeIndex);
|
||||
--count;
|
||||
@ -139,11 +171,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility for remove and iterator.remove: Delete item at position i.
|
||||
* Deletes item at position i.
|
||||
* Utility for remove and iterator.remove.
|
||||
* Call only when holding lock.
|
||||
*/
|
||||
void removeAt(int i) {
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
// if removing front item, just advance
|
||||
if (i == takeIndex) {
|
||||
items[takeIndex] = null;
|
||||
@ -167,69 +200,82 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed)
|
||||
* Creates an {@code ArrayBlockingQueue} with the given (fixed)
|
||||
* capacity and default access policy.
|
||||
*
|
||||
* @param capacity the capacity of this queue
|
||||
* @throws IllegalArgumentException if <tt>capacity</tt> is less than 1
|
||||
* @throws IllegalArgumentException if {@code capacity < 1}
|
||||
*/
|
||||
public ArrayBlockingQueue(int capacity) {
|
||||
this(capacity, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed)
|
||||
* Creates an {@code ArrayBlockingQueue} with the given (fixed)
|
||||
* capacity and the specified access policy.
|
||||
*
|
||||
* @param capacity the capacity of this queue
|
||||
* @param fair if <tt>true</tt> then queue accesses for threads blocked
|
||||
* @param fair if {@code true} then queue accesses for threads blocked
|
||||
* on insertion or removal, are processed in FIFO order;
|
||||
* if <tt>false</tt> the access order is unspecified.
|
||||
* @throws IllegalArgumentException if <tt>capacity</tt> is less than 1
|
||||
* if {@code false} the access order is unspecified.
|
||||
* @throws IllegalArgumentException if {@code capacity < 1}
|
||||
*/
|
||||
public ArrayBlockingQueue(int capacity, boolean fair) {
|
||||
if (capacity <= 0)
|
||||
throw new IllegalArgumentException();
|
||||
this.items = (E[]) new Object[capacity];
|
||||
this.items = new Object[capacity];
|
||||
lock = new ReentrantLock(fair);
|
||||
notEmpty = lock.newCondition();
|
||||
notFull = lock.newCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed)
|
||||
* Creates an {@code ArrayBlockingQueue} with the given (fixed)
|
||||
* capacity, the specified access policy and initially containing the
|
||||
* elements of the given collection,
|
||||
* added in traversal order of the collection's iterator.
|
||||
*
|
||||
* @param capacity the capacity of this queue
|
||||
* @param fair if <tt>true</tt> then queue accesses for threads blocked
|
||||
* @param fair if {@code true} then queue accesses for threads blocked
|
||||
* on insertion or removal, are processed in FIFO order;
|
||||
* if <tt>false</tt> the access order is unspecified.
|
||||
* if {@code false} the access order is unspecified.
|
||||
* @param c the collection of elements to initially contain
|
||||
* @throws IllegalArgumentException if <tt>capacity</tt> is less than
|
||||
* <tt>c.size()</tt>, or less than 1.
|
||||
* @throws IllegalArgumentException if {@code capacity} is less than
|
||||
* {@code c.size()}, or less than 1.
|
||||
* @throws NullPointerException if the specified collection or any
|
||||
* of its elements are null
|
||||
*/
|
||||
public ArrayBlockingQueue(int capacity, boolean fair,
|
||||
Collection<? extends E> c) {
|
||||
this(capacity, fair);
|
||||
if (capacity < c.size())
|
||||
throw new IllegalArgumentException();
|
||||
|
||||
for (E e : c)
|
||||
add(e);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock(); // Lock only for visibility, not mutual exclusion
|
||||
try {
|
||||
int i = 0;
|
||||
try {
|
||||
for (E e : c) {
|
||||
checkNotNull(e);
|
||||
items[i++] = e;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
count = i;
|
||||
putIndex = (i == capacity) ? 0 : i;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the tail of this queue if it is
|
||||
* possible to do so immediately without exceeding the queue's capacity,
|
||||
* returning <tt>true</tt> upon success and throwing an
|
||||
* <tt>IllegalStateException</tt> if this queue is full.
|
||||
* returning {@code true} upon success and throwing an
|
||||
* {@code IllegalStateException} if this queue is full.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
* @throws IllegalStateException if this queue is full
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
@ -240,14 +286,14 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
/**
|
||||
* Inserts the specified element at the tail of this queue if it is
|
||||
* possible to do so immediately without exceeding the queue's capacity,
|
||||
* returning <tt>true</tt> upon success and <tt>false</tt> if this queue
|
||||
* returning {@code true} upon success and {@code false} if this queue
|
||||
* is full. This method is generally preferable to method {@link #add},
|
||||
* which can fail to insert an element only by throwing an exception.
|
||||
*
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offer(E e) {
|
||||
if (e == null) throw new NullPointerException();
|
||||
checkNotNull(e);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
@ -270,18 +316,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
public void put(E e) throws InterruptedException {
|
||||
if (e == null) throw new NullPointerException();
|
||||
final E[] items = this.items;
|
||||
checkNotNull(e);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
try {
|
||||
while (count == items.length)
|
||||
notFull.await();
|
||||
} catch (InterruptedException ie) {
|
||||
notFull.signal(); // propagate to non-interrupted thread
|
||||
throw ie;
|
||||
}
|
||||
while (count == items.length)
|
||||
notFull.await();
|
||||
insert(e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -299,25 +339,18 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
public boolean offer(E e, long timeout, TimeUnit unit)
|
||||
throws InterruptedException {
|
||||
|
||||
if (e == null) throw new NullPointerException();
|
||||
checkNotNull(e);
|
||||
long nanos = unit.toNanos(timeout);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
for (;;) {
|
||||
if (count != items.length) {
|
||||
insert(e);
|
||||
return true;
|
||||
}
|
||||
while (count == items.length) {
|
||||
if (nanos <= 0)
|
||||
return false;
|
||||
try {
|
||||
nanos = notFull.awaitNanos(nanos);
|
||||
} catch (InterruptedException ie) {
|
||||
notFull.signal(); // propagate to non-interrupted thread
|
||||
throw ie;
|
||||
}
|
||||
nanos = notFull.awaitNanos(nanos);
|
||||
}
|
||||
insert(e);
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -327,10 +360,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
if (count == 0)
|
||||
return null;
|
||||
E x = extract();
|
||||
return x;
|
||||
return (count == 0) ? null : extract();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -340,15 +370,9 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
try {
|
||||
while (count == 0)
|
||||
notEmpty.await();
|
||||
} catch (InterruptedException ie) {
|
||||
notEmpty.signal(); // propagate to non-interrupted thread
|
||||
throw ie;
|
||||
}
|
||||
E x = extract();
|
||||
return x;
|
||||
while (count == 0)
|
||||
notEmpty.await();
|
||||
return extract();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -359,21 +383,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lockInterruptibly();
|
||||
try {
|
||||
for (;;) {
|
||||
if (count != 0) {
|
||||
E x = extract();
|
||||
return x;
|
||||
}
|
||||
while (count == 0) {
|
||||
if (nanos <= 0)
|
||||
return null;
|
||||
try {
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
} catch (InterruptedException ie) {
|
||||
notEmpty.signal(); // propagate to non-interrupted thread
|
||||
throw ie;
|
||||
}
|
||||
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
}
|
||||
return extract();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -383,7 +398,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return (count == 0) ? null : items[takeIndex];
|
||||
return (count == 0) ? null : itemAt(takeIndex);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -412,10 +427,10 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* Returns the number of additional elements that this queue can ideally
|
||||
* (in the absence of memory or resource constraints) accept without
|
||||
* blocking. This is always equal to the initial capacity of this queue
|
||||
* less the current <tt>size</tt> of this queue.
|
||||
* less the current {@code size} of this queue.
|
||||
*
|
||||
* <p>Note that you <em>cannot</em> always tell if an attempt to insert
|
||||
* an element will succeed by inspecting <tt>remainingCapacity</tt>
|
||||
* an element will succeed by inspecting {@code remainingCapacity}
|
||||
* because it may be the case that another thread is about to
|
||||
* insert or remove an element.
|
||||
*/
|
||||
@ -431,59 +446,56 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Removes a single instance of the specified element from this queue,
|
||||
* if it is present. More formally, removes an element <tt>e</tt> such
|
||||
* that <tt>o.equals(e)</tt>, if this queue contains one or more such
|
||||
* if it is present. More formally, removes an element {@code e} such
|
||||
* that {@code o.equals(e)}, if this queue contains one or more such
|
||||
* elements.
|
||||
* Returns <tt>true</tt> if this queue contained the specified element
|
||||
* Returns {@code true} if this queue contained the specified element
|
||||
* (or equivalently, if this queue changed as a result of the call).
|
||||
*
|
||||
* <p>Removal of interior elements in circular array based queues
|
||||
* is an intrinsically slow and disruptive operation, so should
|
||||
* be undertaken only in exceptional circumstances, ideally
|
||||
* only when the queue is known not to be accessible by other
|
||||
* threads.
|
||||
*
|
||||
* @param o element to be removed from this queue, if present
|
||||
* @return <tt>true</tt> if this queue changed as a result of the call
|
||||
* @return {@code true} if this queue changed as a result of the call
|
||||
*/
|
||||
public boolean remove(Object o) {
|
||||
if (o == null) return false;
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int i = takeIndex;
|
||||
int k = 0;
|
||||
for (;;) {
|
||||
if (k++ >= count)
|
||||
return false;
|
||||
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
|
||||
if (o.equals(items[i])) {
|
||||
removeAt(i);
|
||||
return true;
|
||||
}
|
||||
i = inc(i);
|
||||
}
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <tt>true</tt> if this queue contains the specified element.
|
||||
* More formally, returns <tt>true</tt> if and only if this queue contains
|
||||
* at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>.
|
||||
* Returns {@code true} if this queue contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this queue contains
|
||||
* at least one element {@code e} such that {@code o.equals(e)}.
|
||||
*
|
||||
* @param o object to be checked for containment in this queue
|
||||
* @return <tt>true</tt> if this queue contains the specified element
|
||||
* @return {@code true} if this queue contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
if (o == null) return false;
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int i = takeIndex;
|
||||
int k = 0;
|
||||
while (k++ < count) {
|
||||
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
|
||||
if (o.equals(items[i]))
|
||||
return true;
|
||||
i = inc(i);
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -504,17 +516,14 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @return an array containing all of the elements in this queue
|
||||
*/
|
||||
public Object[] toArray() {
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
final int count = this.count;
|
||||
Object[] a = new Object[count];
|
||||
int k = 0;
|
||||
int i = takeIndex;
|
||||
while (k < count) {
|
||||
a[k++] = items[i];
|
||||
i = inc(i);
|
||||
}
|
||||
for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
|
||||
a[k] = items[i];
|
||||
return a;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -531,22 +540,22 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* <p>If this queue fits in the specified array with room to spare
|
||||
* (i.e., the array has more elements than this queue), the element in
|
||||
* the array immediately following the end of the queue is set to
|
||||
* <tt>null</tt>.
|
||||
* {@code null}.
|
||||
*
|
||||
* <p>Like the {@link #toArray()} method, this method acts as bridge between
|
||||
* array-based and collection-based APIs. Further, this method allows
|
||||
* precise control over the runtime type of the output array, and may,
|
||||
* under certain circumstances, be used to save allocation costs.
|
||||
*
|
||||
* <p>Suppose <tt>x</tt> is a queue known to contain only strings.
|
||||
* <p>Suppose {@code x} is a queue known to contain only strings.
|
||||
* The following code can be used to dump the queue into a newly
|
||||
* allocated array of <tt>String</tt>:
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre>
|
||||
* String[] y = x.toArray(new String[0]);</pre>
|
||||
*
|
||||
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
|
||||
* <tt>toArray()</tt>.
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
*
|
||||
* @param a the array into which the elements of the queue are to
|
||||
* be stored, if it is big enough; otherwise, a new array of the
|
||||
@ -557,24 +566,20 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* this queue
|
||||
* @throws NullPointerException if the specified array is null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T[] toArray(T[] a) {
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
if (a.length < count)
|
||||
final int count = this.count;
|
||||
final int len = a.length;
|
||||
if (len < count)
|
||||
a = (T[])java.lang.reflect.Array.newInstance(
|
||||
a.getClass().getComponentType(),
|
||||
count
|
||||
);
|
||||
|
||||
int k = 0;
|
||||
int i = takeIndex;
|
||||
while (k < count) {
|
||||
a[k++] = (T)items[i];
|
||||
i = inc(i);
|
||||
}
|
||||
if (a.length > count)
|
||||
a.getClass().getComponentType(), count);
|
||||
for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
|
||||
a[k] = (T) items[i];
|
||||
if (len > count)
|
||||
a[count] = null;
|
||||
return a;
|
||||
} finally {
|
||||
@ -586,7 +591,19 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return super.toString();
|
||||
int k = count;
|
||||
if (k == 0)
|
||||
return "[]";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (int i = takeIndex; ; i = inc(i)) {
|
||||
Object e = items[i];
|
||||
sb.append(e == this ? "(this Collection)" : e);
|
||||
if (--k == 0)
|
||||
return sb.append(']').toString();
|
||||
sb.append(',').append(' ');
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -597,16 +614,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* The queue will be empty after this call returns.
|
||||
*/
|
||||
public void clear() {
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int i = takeIndex;
|
||||
int k = count;
|
||||
while (k-- > 0) {
|
||||
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
|
||||
items[i] = null;
|
||||
i = inc(i);
|
||||
}
|
||||
count = 0;
|
||||
putIndex = 0;
|
||||
takeIndex = 0;
|
||||
@ -623,11 +636,10 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @throws IllegalArgumentException {@inheritDoc}
|
||||
*/
|
||||
public int drainTo(Collection<? super E> c) {
|
||||
if (c == null)
|
||||
throw new NullPointerException();
|
||||
checkNotNull(c);
|
||||
if (c == this)
|
||||
throw new IllegalArgumentException();
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
@ -635,7 +647,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
int n = 0;
|
||||
int max = count;
|
||||
while (n < max) {
|
||||
c.add(items[i]);
|
||||
c.add(this.<E>cast(items[i]));
|
||||
items[i] = null;
|
||||
i = inc(i);
|
||||
++n;
|
||||
@ -659,22 +671,20 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @throws IllegalArgumentException {@inheritDoc}
|
||||
*/
|
||||
public int drainTo(Collection<? super E> c, int maxElements) {
|
||||
if (c == null)
|
||||
throw new NullPointerException();
|
||||
checkNotNull(c);
|
||||
if (c == this)
|
||||
throw new IllegalArgumentException();
|
||||
if (maxElements <= 0)
|
||||
return 0;
|
||||
final E[] items = this.items;
|
||||
final Object[] items = this.items;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
int i = takeIndex;
|
||||
int n = 0;
|
||||
int sz = count;
|
||||
int max = (maxElements < count)? maxElements : count;
|
||||
int max = (maxElements < count) ? maxElements : count;
|
||||
while (n < max) {
|
||||
c.add(items[i]);
|
||||
c.add(this.<E>cast(items[i]));
|
||||
items[i] = null;
|
||||
i = inc(i);
|
||||
++n;
|
||||
@ -690,11 +700,13 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over the elements in this queue in proper sequence.
|
||||
* The returned <tt>Iterator</tt> is a "weakly consistent" iterator that
|
||||
* will never throw {@link ConcurrentModificationException},
|
||||
* The elements will be returned in order from first (head) to last (tail).
|
||||
*
|
||||
* <p>The returned {@code Iterator} is a "weakly consistent" iterator that
|
||||
* will never throw {@link java.util.ConcurrentModificationException
|
||||
* ConcurrentModificationException},
|
||||
* and guarantees to traverse elements as they existed upon
|
||||
* construction of the iterator, and may (but is not guaranteed to)
|
||||
* reflect any modifications subsequent to construction.
|
||||
@ -702,83 +714,65 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @return an iterator over the elements in this queue in proper sequence
|
||||
*/
|
||||
public Iterator<E> iterator() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return new Itr();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return new Itr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterator for ArrayBlockingQueue
|
||||
* Iterator for ArrayBlockingQueue. To maintain weak consistency
|
||||
* with respect to puts and takes, we (1) read ahead one slot, so
|
||||
* as to not report hasNext true but then not have an element to
|
||||
* return -- however we later recheck this slot to use the most
|
||||
* current value; (2) ensure that each array slot is traversed at
|
||||
* most once (by tracking "remaining" elements); (3) skip over
|
||||
* null slots, which can occur if takes race ahead of iterators.
|
||||
* However, for circular array-based queues, we cannot rely on any
|
||||
* well established definition of what it means to be weakly
|
||||
* consistent with respect to interior removes since these may
|
||||
* require slot overwrites in the process of sliding elements to
|
||||
* cover gaps. So we settle for resiliency, operating on
|
||||
* established apparent nexts, which may miss some elements that
|
||||
* have moved between calls to next.
|
||||
*/
|
||||
private class Itr implements Iterator<E> {
|
||||
/**
|
||||
* Index of element to be returned by next,
|
||||
* or a negative number if no such.
|
||||
*/
|
||||
private int nextIndex;
|
||||
|
||||
/**
|
||||
* nextItem holds on to item fields because once we claim
|
||||
* that an element exists in hasNext(), we must return it in
|
||||
* the following next() call even if it was in the process of
|
||||
* being removed when hasNext() was called.
|
||||
*/
|
||||
private E nextItem;
|
||||
|
||||
/**
|
||||
* Index of element returned by most recent call to next.
|
||||
* Reset to -1 if this element is deleted by a call to remove.
|
||||
*/
|
||||
private int lastRet;
|
||||
private int remaining; // Number of elements yet to be returned
|
||||
private int nextIndex; // Index of element to be returned by next
|
||||
private E nextItem; // Element to be returned by next call to next
|
||||
private E lastItem; // Element returned by last call to next
|
||||
private int lastRet; // Index of last element returned, or -1 if none
|
||||
|
||||
Itr() {
|
||||
lastRet = -1;
|
||||
if (count == 0)
|
||||
nextIndex = -1;
|
||||
else {
|
||||
nextIndex = takeIndex;
|
||||
nextItem = items[takeIndex];
|
||||
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
lastRet = -1;
|
||||
if ((remaining = count) > 0)
|
||||
nextItem = itemAt(nextIndex = takeIndex);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
/*
|
||||
* No sync. We can return true by mistake here
|
||||
* only if this iterator passed across threads,
|
||||
* which we don't support anyway.
|
||||
*/
|
||||
return nextIndex >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether nextIndex is valid; if so setting nextItem.
|
||||
* Stops iterator when either hits putIndex or sees null item.
|
||||
*/
|
||||
private void checkNext() {
|
||||
if (nextIndex == putIndex) {
|
||||
nextIndex = -1;
|
||||
nextItem = null;
|
||||
} else {
|
||||
nextItem = items[nextIndex];
|
||||
if (nextItem == null)
|
||||
nextIndex = -1;
|
||||
}
|
||||
return remaining > 0;
|
||||
}
|
||||
|
||||
public E next() {
|
||||
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
if (nextIndex < 0)
|
||||
if (remaining <= 0)
|
||||
throw new NoSuchElementException();
|
||||
lastRet = nextIndex;
|
||||
E x = nextItem;
|
||||
nextIndex = inc(nextIndex);
|
||||
checkNext();
|
||||
E x = itemAt(nextIndex); // check for fresher value
|
||||
if (x == null) {
|
||||
x = nextItem; // we are forced to report old value
|
||||
lastItem = null; // but ensure remove fails
|
||||
}
|
||||
else
|
||||
lastItem = x;
|
||||
while (--remaining > 0 && // skip over nulls
|
||||
(nextItem = itemAt(nextIndex = inc(nextIndex))) == null)
|
||||
;
|
||||
return x;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
@ -793,15 +787,19 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
|
||||
if (i == -1)
|
||||
throw new IllegalStateException();
|
||||
lastRet = -1;
|
||||
|
||||
int ti = takeIndex;
|
||||
removeAt(i);
|
||||
// back up cursor (reset to front if was first element)
|
||||
nextIndex = (i == ti) ? takeIndex : i;
|
||||
checkNext();
|
||||
E x = lastItem;
|
||||
lastItem = null;
|
||||
// only remove if item still at index
|
||||
if (x != null && x == items[i]) {
|
||||
boolean removingHead = (i == takeIndex);
|
||||
removeAt(i);
|
||||
if (!removingHead)
|
||||
nextIndex = dec(nextIndex);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -869,6 +869,8 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the front of this deque.
|
||||
* As the deque is unbounded, this method will never throw
|
||||
* {@link IllegalStateException}.
|
||||
*
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
@ -878,6 +880,8 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the end of this deque.
|
||||
* As the deque is unbounded, this method will never throw
|
||||
* {@link IllegalStateException}.
|
||||
*
|
||||
* <p>This method is equivalent to {@link #add}.
|
||||
*
|
||||
@ -889,8 +893,9 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the front of this deque.
|
||||
* As the deque is unbounded, this method will never return {@code false}.
|
||||
*
|
||||
* @return {@code true} always
|
||||
* @return {@code true} (as specified by {@link Deque#offerFirst})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offerFirst(E e) {
|
||||
@ -900,10 +905,11 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the end of this deque.
|
||||
* As the deque is unbounded, this method will never return {@code false}.
|
||||
*
|
||||
* <p>This method is equivalent to {@link #add}.
|
||||
*
|
||||
* @return {@code true} always
|
||||
* @return {@code true} (as specified by {@link Deque#offerLast})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offerLast(E e) {
|
||||
@ -983,6 +989,7 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the tail of this deque.
|
||||
* As the deque is unbounded, this method will never return {@code false}.
|
||||
*
|
||||
* @return {@code true} (as specified by {@link Queue#offer})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
@ -993,6 +1000,8 @@ public class ConcurrentLinkedDeque<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the tail of this deque.
|
||||
* As the deque is unbounded, this method will never throw
|
||||
* {@link IllegalStateException} or return {@code false}.
|
||||
*
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
|
@ -269,6 +269,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the tail of this queue.
|
||||
* As the queue is unbounded, this method will never throw
|
||||
* {@link IllegalStateException} or return {@code false}.
|
||||
*
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
@ -298,6 +300,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element at the tail of this queue.
|
||||
* As the queue is unbounded, this method will never return {@code false}.
|
||||
*
|
||||
* @return {@code true} (as specified by {@link Queue#offer})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
|
@ -374,17 +374,11 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
null, null, 1);
|
||||
}
|
||||
|
||||
/** Updater for casHead */
|
||||
private static final
|
||||
AtomicReferenceFieldUpdater<ConcurrentSkipListMap, HeadIndex>
|
||||
headUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(ConcurrentSkipListMap.class, HeadIndex.class, "head");
|
||||
|
||||
/**
|
||||
* compareAndSet head node
|
||||
*/
|
||||
private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
|
||||
return headUpdater.compareAndSet(this, cmp, val);
|
||||
return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
|
||||
}
|
||||
|
||||
/* ---------------- Nodes -------------- */
|
||||
@ -423,28 +417,18 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/** Updater for casNext */
|
||||
static final AtomicReferenceFieldUpdater<Node, Node>
|
||||
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(Node.class, Node.class, "next");
|
||||
|
||||
/** Updater for casValue */
|
||||
static final AtomicReferenceFieldUpdater<Node, Object>
|
||||
valueUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(Node.class, Object.class, "value");
|
||||
|
||||
/**
|
||||
* compareAndSet value field
|
||||
*/
|
||||
boolean casValue(Object cmp, Object val) {
|
||||
return valueUpdater.compareAndSet(this, cmp, val);
|
||||
return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* compareAndSet next field
|
||||
*/
|
||||
boolean casNext(Node<K,V> cmp, Node<K,V> val) {
|
||||
return nextUpdater.compareAndSet(this, cmp, val);
|
||||
return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -522,6 +506,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
return null;
|
||||
return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long valueOffset =
|
||||
objectFieldOffset(UNSAFE, "value", Node.class);
|
||||
private static final long nextOffset =
|
||||
objectFieldOffset(UNSAFE, "next", Node.class);
|
||||
|
||||
}
|
||||
|
||||
/* ---------------- Indexing -------------- */
|
||||
@ -547,16 +539,11 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/** Updater for casRight */
|
||||
static final AtomicReferenceFieldUpdater<Index, Index>
|
||||
rightUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(Index.class, Index.class, "right");
|
||||
|
||||
/**
|
||||
* compareAndSet right field
|
||||
*/
|
||||
final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
|
||||
return rightUpdater.compareAndSet(this, cmp, val);
|
||||
return UNSAFE.compareAndSwapObject(this, rightOffset, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -591,6 +578,12 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
final boolean unlink(Index<K,V> succ) {
|
||||
return !indexesDeletedNode() && casRight(succ, succ.right);
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long rightOffset =
|
||||
objectFieldOffset(UNSAFE, "right", Index.class);
|
||||
|
||||
}
|
||||
|
||||
/* ---------------- Head nodes -------------- */
|
||||
@ -640,7 +633,8 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
* cast key as Comparable, which may cause ClassCastException,
|
||||
* which is propagated back to caller.
|
||||
*/
|
||||
private Comparable<? super K> comparable(Object key) throws ClassCastException {
|
||||
private Comparable<? super K> comparable(Object key)
|
||||
throws ClassCastException {
|
||||
if (key == null)
|
||||
throw new NullPointerException();
|
||||
if (comparator != null)
|
||||
@ -799,68 +793,12 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized variant of findNode to perform Map.get. Does a weak
|
||||
* traversal, not bothering to fix any deleted index nodes,
|
||||
* returning early if it happens to see key in index, and passing
|
||||
* over any deleted base nodes, falling back to getUsingFindNode
|
||||
* only if it would otherwise return value from an ongoing
|
||||
* deletion. Also uses "bound" to eliminate need for some
|
||||
* comparisons (see Pugh Cookbook). Also folds uses of null checks
|
||||
* and node-skipping because markers have null keys.
|
||||
* Gets value for key using findNode.
|
||||
* @param okey the key
|
||||
* @return the value, or null if absent
|
||||
*/
|
||||
private V doGet(Object okey) {
|
||||
Comparable<? super K> key = comparable(okey);
|
||||
Node<K,V> bound = null;
|
||||
Index<K,V> q = head;
|
||||
Index<K,V> r = q.right;
|
||||
Node<K,V> n;
|
||||
K k;
|
||||
int c;
|
||||
for (;;) {
|
||||
Index<K,V> d;
|
||||
// Traverse rights
|
||||
if (r != null && (n = r.node) != bound && (k = n.key) != null) {
|
||||
if ((c = key.compareTo(k)) > 0) {
|
||||
q = r;
|
||||
r = r.right;
|
||||
continue;
|
||||
} else if (c == 0) {
|
||||
Object v = n.value;
|
||||
return (v != null)? (V)v : getUsingFindNode(key);
|
||||
} else
|
||||
bound = n;
|
||||
}
|
||||
|
||||
// Traverse down
|
||||
if ((d = q.down) != null) {
|
||||
q = d;
|
||||
r = d.right;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// Traverse nexts
|
||||
for (n = q.node.next; n != null; n = n.next) {
|
||||
if ((k = n.key) != null) {
|
||||
if ((c = key.compareTo(k)) == 0) {
|
||||
Object v = n.value;
|
||||
return (v != null)? (V)v : getUsingFindNode(key);
|
||||
} else if (c < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs map.get via findNode. Used as a backup if doGet
|
||||
* encounters an in-progress deletion.
|
||||
* @param key the key
|
||||
* @return the value, or null if absent
|
||||
*/
|
||||
private V getUsingFindNode(Comparable<? super K> key) {
|
||||
/*
|
||||
* Loop needed here and elsewhere in case value field goes
|
||||
* null just as it is about to be returned, in which case we
|
||||
@ -943,7 +881,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
x ^= x << 13;
|
||||
x ^= x >>> 17;
|
||||
randomSeed = x ^= x << 5;
|
||||
if ((x & 0x8001) != 0) // test highest and lowest bits
|
||||
if ((x & 0x80000001) != 0) // test highest and lowest bits
|
||||
return 0;
|
||||
int level = 1;
|
||||
while (((x >>>= 1) & 1) != 0) ++level;
|
||||
@ -1256,7 +1194,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
Node<K,V> n = b.next;
|
||||
for (;;) {
|
||||
if (n == null)
|
||||
return (b.isBaseHeader())? null : b;
|
||||
return b.isBaseHeader() ? null : b;
|
||||
Node<K,V> f = n.next; // inconsistent read
|
||||
if (n != b.next)
|
||||
break;
|
||||
@ -1374,7 +1312,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
Node<K,V> n = b.next;
|
||||
for (;;) {
|
||||
if (n == null)
|
||||
return ((rel & LT) == 0 || b.isBaseHeader())? null : b;
|
||||
return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
|
||||
Node<K,V> f = n.next;
|
||||
if (n != b.next) // inconsistent read
|
||||
break;
|
||||
@ -1390,7 +1328,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
(c < 0 && (rel & LT) == 0))
|
||||
return n;
|
||||
if ( c <= 0 && (rel & LT) != 0)
|
||||
return (b.isBaseHeader())? null : b;
|
||||
return b.isBaseHeader() ? null : b;
|
||||
b = n;
|
||||
n = f;
|
||||
}
|
||||
@ -1744,7 +1682,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
if (n.getValidValue() != null)
|
||||
++count;
|
||||
}
|
||||
return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count;
|
||||
return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2099,7 +2037,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
*/
|
||||
public K lowerKey(K key) {
|
||||
Node<K,V> n = findNear(key, LT);
|
||||
return (n == null)? null : n.key;
|
||||
return (n == null) ? null : n.key;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2123,7 +2061,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
*/
|
||||
public K floorKey(K key) {
|
||||
Node<K,V> n = findNear(key, LT|EQ);
|
||||
return (n == null)? null : n.key;
|
||||
return (n == null) ? null : n.key;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2145,7 +2083,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
*/
|
||||
public K ceilingKey(K key) {
|
||||
Node<K,V> n = findNear(key, GT|EQ);
|
||||
return (n == null)? null : n.key;
|
||||
return (n == null) ? null : n.key;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2169,7 +2107,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
*/
|
||||
public K higherKey(K key) {
|
||||
Node<K,V> n = findNear(key, GT);
|
||||
return (n == null)? null : n.key;
|
||||
return (n == null) ? null : n.key;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2342,7 +2280,8 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
return list;
|
||||
}
|
||||
|
||||
static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
|
||||
static final class KeySet<E>
|
||||
extends AbstractSet<E> implements NavigableSet<E> {
|
||||
private final ConcurrentNavigableMap<E,Object> m;
|
||||
KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; }
|
||||
public int size() { return m.size(); }
|
||||
@ -2359,11 +2298,11 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
public E last() { return m.lastKey(); }
|
||||
public E pollFirst() {
|
||||
Map.Entry<E,Object> e = m.pollFirstEntry();
|
||||
return e == null? null : e.getKey();
|
||||
return (e == null) ? null : e.getKey();
|
||||
}
|
||||
public E pollLast() {
|
||||
Map.Entry<E,Object> e = m.pollLastEntry();
|
||||
return e == null? null : e.getKey();
|
||||
return (e == null) ? null : e.getKey();
|
||||
}
|
||||
public Iterator<E> iterator() {
|
||||
if (m instanceof ConcurrentSkipListMap)
|
||||
@ -2710,9 +2649,9 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
rel &= ~m.LT;
|
||||
}
|
||||
if (tooLow(key))
|
||||
return ((rel & m.LT) != 0)? null : lowestEntry();
|
||||
return ((rel & m.LT) != 0) ? null : lowestEntry();
|
||||
if (tooHigh(key))
|
||||
return ((rel & m.LT) != 0)? highestEntry() : null;
|
||||
return ((rel & m.LT) != 0) ? highestEntry() : null;
|
||||
for (;;) {
|
||||
Node<K,V> n = m.findNear(key, rel);
|
||||
if (n == null || !inBounds(n.key))
|
||||
@ -2783,7 +2722,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
|
||||
public V remove(Object key) {
|
||||
K k = (K)key;
|
||||
return (!inBounds(k))? null : m.remove(k);
|
||||
return (!inBounds(k)) ? null : m.remove(k);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
@ -2794,7 +2733,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
if (n.getValidValue() != null)
|
||||
++count;
|
||||
}
|
||||
return count >= Integer.MAX_VALUE? Integer.MAX_VALUE : (int)count;
|
||||
return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
@ -2972,27 +2911,27 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
|
||||
public K firstKey() {
|
||||
return isDescending? highestKey() : lowestKey();
|
||||
return isDescending ? highestKey() : lowestKey();
|
||||
}
|
||||
|
||||
public K lastKey() {
|
||||
return isDescending? lowestKey() : highestKey();
|
||||
return isDescending ? lowestKey() : highestKey();
|
||||
}
|
||||
|
||||
public Map.Entry<K,V> firstEntry() {
|
||||
return isDescending? highestEntry() : lowestEntry();
|
||||
return isDescending ? highestEntry() : lowestEntry();
|
||||
}
|
||||
|
||||
public Map.Entry<K,V> lastEntry() {
|
||||
return isDescending? lowestEntry() : highestEntry();
|
||||
return isDescending ? lowestEntry() : highestEntry();
|
||||
}
|
||||
|
||||
public Map.Entry<K,V> pollFirstEntry() {
|
||||
return isDescending? removeHighest() : removeLowest();
|
||||
return isDescending ? removeHighest() : removeLowest();
|
||||
}
|
||||
|
||||
public Map.Entry<K,V> pollLastEntry() {
|
||||
return isDescending? removeLowest() : removeHighest();
|
||||
return isDescending ? removeLowest() : removeHighest();
|
||||
}
|
||||
|
||||
/* ---------------- Submap Views -------------- */
|
||||
@ -3141,4 +3080,22 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long headOffset =
|
||||
objectFieldOffset(UNSAFE, "head", ConcurrentSkipListMap.class);
|
||||
|
||||
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
|
||||
String field, Class<?> klazz) {
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Convert Exception to corresponding Error
|
||||
NoSuchFieldError error = new NoSuchFieldError(field);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -832,7 +832,7 @@ public class CopyOnWriteArrayList<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the state of the list to a stream (i.e., serialize it).
|
||||
* Saves the state of the list to a stream (that is, serializes it).
|
||||
*
|
||||
* @serialData The length of the array backing the list is emitted
|
||||
* (int), followed by all of its elements (each an Object)
|
||||
@ -842,27 +842,25 @@ public class CopyOnWriteArrayList<E>
|
||||
private void writeObject(java.io.ObjectOutputStream s)
|
||||
throws java.io.IOException{
|
||||
|
||||
// Write out element count, and any hidden stuff
|
||||
s.defaultWriteObject();
|
||||
|
||||
Object[] elements = getArray();
|
||||
int len = elements.length;
|
||||
// Write out array length
|
||||
s.writeInt(len);
|
||||
s.writeInt(elements.length);
|
||||
|
||||
// Write out all elements in the proper order.
|
||||
for (int i = 0; i < len; i++)
|
||||
s.writeObject(elements[i]);
|
||||
for (Object element : elements)
|
||||
s.writeObject(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstitute the list from a stream (i.e., deserialize it).
|
||||
* Reconstitutes the list from a stream (that is, deserializes it).
|
||||
*
|
||||
* @param s the stream
|
||||
*/
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
|
||||
// Read in size, and any hidden stuff
|
||||
s.defaultReadObject();
|
||||
|
||||
// bind to new lock
|
||||
|
@ -525,8 +525,8 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
*/
|
||||
private volatile long eventWaiters;
|
||||
|
||||
private static final int EVENT_COUNT_SHIFT = 32;
|
||||
private static final long WAITER_ID_MASK = (1L << 16) - 1L;
|
||||
private static final int EVENT_COUNT_SHIFT = 32;
|
||||
private static final int WAITER_ID_MASK = (1 << 16) - 1;
|
||||
|
||||
/**
|
||||
* A counter for events that may wake up worker threads:
|
||||
@ -615,7 +615,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
// are usually manually inlined by callers
|
||||
|
||||
/**
|
||||
* Increments running count part of workerCounts
|
||||
* Increments running count part of workerCounts.
|
||||
*/
|
||||
final void incrementRunningCount() {
|
||||
int c;
|
||||
@ -625,7 +625,17 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to decrement running count unless already zero
|
||||
* Tries to increment running count part of workerCounts.
|
||||
*/
|
||||
final boolean tryIncrementRunningCount() {
|
||||
int c;
|
||||
return UNSAFE.compareAndSwapInt(this, workerCountsOffset,
|
||||
c = workerCounts,
|
||||
c + ONE_RUNNING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to decrement running count unless already zero.
|
||||
*/
|
||||
final boolean tryDecrementRunningCount() {
|
||||
int wc = workerCounts;
|
||||
@ -698,10 +708,11 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
for (k = 0; k < n && ws[k] != null; ++k)
|
||||
;
|
||||
if (k == n)
|
||||
ws = Arrays.copyOf(ws, n << 1);
|
||||
ws = workers = Arrays.copyOf(ws, n << 1);
|
||||
}
|
||||
ws[k] = w;
|
||||
workers = ws; // volatile array write ensures slot visibility
|
||||
int c = eventCount; // advance event count to ensure visibility
|
||||
UNSAFE.compareAndSwapInt(this, eventCountOffset, c, c+1);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -734,7 +745,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
*/
|
||||
final void workerTerminated(ForkJoinWorkerThread w) {
|
||||
forgetWorker(w);
|
||||
decrementWorkerCounts(w.isTrimmed()? 0 : ONE_RUNNING, ONE_TOTAL);
|
||||
decrementWorkerCounts(w.isTrimmed() ? 0 : ONE_RUNNING, ONE_TOTAL);
|
||||
while (w.stealCount != 0) // collect final count
|
||||
tryAccumulateStealCount(w);
|
||||
tryTerminate(false);
|
||||
@ -746,24 +757,23 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* Releases workers blocked on a count not equal to current count.
|
||||
* Normally called after precheck that eventWaiters isn't zero to
|
||||
* avoid wasted array checks. Gives up upon a change in count or
|
||||
* upon releasing two workers, letting others take over.
|
||||
* upon releasing four workers, letting others take over.
|
||||
*/
|
||||
private void releaseEventWaiters() {
|
||||
ForkJoinWorkerThread[] ws = workers;
|
||||
int n = ws.length;
|
||||
long h = eventWaiters;
|
||||
int ec = eventCount;
|
||||
boolean releasedOne = false;
|
||||
int releases = 4;
|
||||
ForkJoinWorkerThread w; int id;
|
||||
while ((id = ((int)(h & WAITER_ID_MASK)) - 1) >= 0 &&
|
||||
while ((id = (((int)h) & WAITER_ID_MASK) - 1) >= 0 &&
|
||||
(int)(h >>> EVENT_COUNT_SHIFT) != ec &&
|
||||
id < n && (w = ws[id]) != null) {
|
||||
if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
|
||||
h, w.nextWaiter)) {
|
||||
LockSupport.unpark(w);
|
||||
if (releasedOne) // exit on second release
|
||||
if (--releases == 0)
|
||||
break;
|
||||
releasedOne = true;
|
||||
}
|
||||
if (eventCount != ec)
|
||||
break;
|
||||
@ -793,7 +803,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1));
|
||||
long h;
|
||||
while ((runState < SHUTDOWN || !tryTerminate(false)) &&
|
||||
(((int)((h = eventWaiters) & WAITER_ID_MASK)) == 0 ||
|
||||
(((int)(h = eventWaiters) & WAITER_ID_MASK) == 0 ||
|
||||
(int)(h >>> EVENT_COUNT_SHIFT) == ec) &&
|
||||
eventCount == ec) {
|
||||
if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
|
||||
@ -820,9 +830,9 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
if (tryAccumulateStealCount(w)) { // transfer while idle
|
||||
boolean untimed = (w.nextWaiter != 0L ||
|
||||
(workerCounts & RUNNING_COUNT_MASK) <= 1);
|
||||
long startTime = untimed? 0 : System.nanoTime();
|
||||
long startTime = untimed ? 0 : System.nanoTime();
|
||||
Thread.interrupted(); // clear/ignore interrupt
|
||||
if (eventCount != ec || w.isTerminating())
|
||||
if (w.isTerminating() || eventCount != ec)
|
||||
break; // recheck after clear
|
||||
if (untimed)
|
||||
LockSupport.park(w);
|
||||
@ -860,7 +870,8 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
if ((sw = spareWaiters) != 0 &&
|
||||
(id = (sw & SPARE_ID_MASK) - 1) >= 0 &&
|
||||
id < n && (w = ws[id]) != null &&
|
||||
(workerCounts & RUNNING_COUNT_MASK) < parallelism &&
|
||||
(runState >= TERMINATING ||
|
||||
(workerCounts & RUNNING_COUNT_MASK) < parallelism) &&
|
||||
spareWaiters == sw &&
|
||||
UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
|
||||
sw, w.nextSpare)) {
|
||||
@ -914,12 +925,8 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
break;
|
||||
}
|
||||
w.start(recordWorker(w), ueh);
|
||||
if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc) {
|
||||
int c; // advance event count
|
||||
UNSAFE.compareAndSwapInt(this, eventCountOffset,
|
||||
c = eventCount, c+1);
|
||||
if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc)
|
||||
break; // add at most one unless total below target
|
||||
}
|
||||
}
|
||||
}
|
||||
if (eventWaiters != 0L)
|
||||
@ -955,7 +962,7 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
}
|
||||
else if ((h = eventWaiters) != 0L) {
|
||||
long nh;
|
||||
int id = ((int)(h & WAITER_ID_MASK)) - 1;
|
||||
int id = (((int)h) & WAITER_ID_MASK) - 1;
|
||||
if (id >= 0 && id < n && (w = ws[id]) != null &&
|
||||
(nh = w.nextWaiter) != 0L && // keep at least one worker
|
||||
UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh))
|
||||
@ -1003,24 +1010,31 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
int pc = parallelism;
|
||||
while (w.runState == 0) {
|
||||
int rs = runState;
|
||||
if (rs >= TERMINATING) { // propagate shutdown
|
||||
if (rs >= TERMINATING) { // propagate shutdown
|
||||
w.shutdown();
|
||||
break;
|
||||
}
|
||||
if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) &&
|
||||
UNSAFE.compareAndSwapInt(this, runStateOffset, rs, rs - 1))
|
||||
UNSAFE.compareAndSwapInt(this, runStateOffset, rs, --rs)) {
|
||||
inactivate = active = w.active = false;
|
||||
int wc = workerCounts;
|
||||
if (rs == SHUTDOWN) { // all inactive and shut down
|
||||
tryTerminate(false);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int wc = workerCounts; // try to suspend as spare
|
||||
if ((wc & RUNNING_COUNT_MASK) > pc) {
|
||||
if (!(inactivate |= active) && // must inactivate to suspend
|
||||
workerCounts == wc && // try to suspend as spare
|
||||
workerCounts == wc &&
|
||||
UNSAFE.compareAndSwapInt(this, workerCountsOffset,
|
||||
wc, wc - ONE_RUNNING))
|
||||
w.suspendAsSpare();
|
||||
}
|
||||
else if ((wc >>> TOTAL_COUNT_SHIFT) < pc)
|
||||
helpMaintainParallelism(); // not enough workers
|
||||
else if (!ran) {
|
||||
else if (ran)
|
||||
break;
|
||||
else {
|
||||
long h = eventWaiters;
|
||||
int ec = eventCount;
|
||||
if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec)
|
||||
@ -1032,8 +1046,6 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
else if (!(inactivate |= active))
|
||||
eventSync(w, wec); // must inactivate before sync
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1043,35 +1055,67 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
*
|
||||
* @param joinMe the task to join
|
||||
* @param worker the current worker thread
|
||||
* @param timed true if wait should time out
|
||||
* @param nanos timeout value if timed
|
||||
*/
|
||||
final void awaitJoin(ForkJoinTask<?> joinMe, ForkJoinWorkerThread worker) {
|
||||
final void awaitJoin(ForkJoinTask<?> joinMe, ForkJoinWorkerThread worker,
|
||||
boolean timed, long nanos) {
|
||||
long startTime = timed ? System.nanoTime() : 0L;
|
||||
int retries = 2 + (parallelism >> 2); // #helpJoins before blocking
|
||||
boolean running = true; // false when count decremented
|
||||
while (joinMe.status >= 0) {
|
||||
int wc;
|
||||
worker.helpJoinTask(joinMe);
|
||||
if (runState >= TERMINATING) {
|
||||
joinMe.cancelIgnoringExceptions();
|
||||
break;
|
||||
}
|
||||
running = worker.helpJoinTask(joinMe, running);
|
||||
if (joinMe.status < 0)
|
||||
break;
|
||||
else if (retries > 0)
|
||||
if (retries > 0) {
|
||||
--retries;
|
||||
else if (((wc = workerCounts) & RUNNING_COUNT_MASK) != 0 &&
|
||||
UNSAFE.compareAndSwapInt(this, workerCountsOffset,
|
||||
wc, wc - ONE_RUNNING)) {
|
||||
int stat, c; long h;
|
||||
while ((stat = joinMe.status) >= 0 &&
|
||||
(h = eventWaiters) != 0L && // help release others
|
||||
(int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
|
||||
releaseEventWaiters();
|
||||
if (stat >= 0 &&
|
||||
((workerCounts & RUNNING_COUNT_MASK) == 0 ||
|
||||
(stat =
|
||||
joinMe.internalAwaitDone(JOIN_TIMEOUT_MILLIS)) >= 0))
|
||||
helpMaintainParallelism(); // timeout or no running workers
|
||||
do {} while (!UNSAFE.compareAndSwapInt
|
||||
(this, workerCountsOffset,
|
||||
c = workerCounts, c + ONE_RUNNING));
|
||||
if (stat < 0)
|
||||
break; // else restart
|
||||
continue;
|
||||
}
|
||||
int wc = workerCounts;
|
||||
if ((wc & RUNNING_COUNT_MASK) != 0) {
|
||||
if (running) {
|
||||
if (!UNSAFE.compareAndSwapInt(this, workerCountsOffset,
|
||||
wc, wc - ONE_RUNNING))
|
||||
continue;
|
||||
running = false;
|
||||
}
|
||||
long h = eventWaiters;
|
||||
if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
|
||||
releaseEventWaiters();
|
||||
if ((workerCounts & RUNNING_COUNT_MASK) != 0) {
|
||||
long ms; int ns;
|
||||
if (!timed) {
|
||||
ms = JOIN_TIMEOUT_MILLIS;
|
||||
ns = 0;
|
||||
}
|
||||
else { // at most JOIN_TIMEOUT_MILLIS per wait
|
||||
long nt = nanos - (System.nanoTime() - startTime);
|
||||
if (nt <= 0L)
|
||||
break;
|
||||
ms = nt / 1000000;
|
||||
if (ms > JOIN_TIMEOUT_MILLIS) {
|
||||
ms = JOIN_TIMEOUT_MILLIS;
|
||||
ns = 0;
|
||||
}
|
||||
else
|
||||
ns = (int) (nt % 1000000);
|
||||
}
|
||||
joinMe.internalAwaitDone(ms, ns);
|
||||
}
|
||||
if (joinMe.status < 0)
|
||||
break;
|
||||
}
|
||||
helpMaintainParallelism();
|
||||
}
|
||||
if (!running) {
|
||||
int c;
|
||||
do {} while (!UNSAFE.compareAndSwapInt
|
||||
(this, workerCountsOffset,
|
||||
c = workerCounts, c + ONE_RUNNING));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1082,9 +1126,10 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
throws InterruptedException {
|
||||
while (!blocker.isReleasable()) {
|
||||
int wc = workerCounts;
|
||||
if ((wc & RUNNING_COUNT_MASK) != 0 &&
|
||||
UNSAFE.compareAndSwapInt(this, workerCountsOffset,
|
||||
wc, wc - ONE_RUNNING)) {
|
||||
if ((wc & RUNNING_COUNT_MASK) == 0)
|
||||
helpMaintainParallelism();
|
||||
else if (UNSAFE.compareAndSwapInt(this, workerCountsOffset,
|
||||
wc, wc - ONE_RUNNING)) {
|
||||
try {
|
||||
while (!blocker.isReleasable()) {
|
||||
long h = eventWaiters;
|
||||
@ -1129,12 +1174,11 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
// Finish now if all threads terminated; else in some subsequent call
|
||||
if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) {
|
||||
advanceRunLevel(TERMINATED);
|
||||
termination.arrive();
|
||||
termination.forceTermination();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Actions on transition to TERMINATING
|
||||
*
|
||||
@ -1325,17 +1369,13 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
// Execution methods
|
||||
|
||||
/**
|
||||
* Common code for execute, invoke and submit
|
||||
* Submits task and creates, starts, or resumes some workers if necessary
|
||||
*/
|
||||
private <T> void doSubmit(ForkJoinTask<T> task) {
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
if (runState >= SHUTDOWN)
|
||||
throw new RejectedExecutionException();
|
||||
submissionQueue.offer(task);
|
||||
int c; // try to increment event count -- CAS failure OK
|
||||
UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
|
||||
helpMaintainParallelism(); // create, start, or resume some workers
|
||||
helpMaintainParallelism();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1348,8 +1388,33 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public <T> T invoke(ForkJoinTask<T> task) {
|
||||
doSubmit(task);
|
||||
return task.join();
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
if (runState >= SHUTDOWN)
|
||||
throw new RejectedExecutionException();
|
||||
Thread t = Thread.currentThread();
|
||||
if ((t instanceof ForkJoinWorkerThread) &&
|
||||
((ForkJoinWorkerThread)t).pool == this)
|
||||
return task.invoke(); // bypass submit if in same pool
|
||||
else {
|
||||
doSubmit(task);
|
||||
return task.join();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unless terminating, forks task if within an ongoing FJ
|
||||
* computation in the current pool, else submits as external task.
|
||||
*/
|
||||
private <T> void forkOrSubmit(ForkJoinTask<T> task) {
|
||||
if (runState >= SHUTDOWN)
|
||||
throw new RejectedExecutionException();
|
||||
Thread t = Thread.currentThread();
|
||||
if ((t instanceof ForkJoinWorkerThread) &&
|
||||
((ForkJoinWorkerThread)t).pool == this)
|
||||
task.fork();
|
||||
else
|
||||
doSubmit(task);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1361,7 +1426,9 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public void execute(ForkJoinTask<?> task) {
|
||||
doSubmit(task);
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
forkOrSubmit(task);
|
||||
}
|
||||
|
||||
// AbstractExecutorService methods
|
||||
@ -1372,12 +1439,14 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public void execute(Runnable task) {
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
ForkJoinTask<?> job;
|
||||
if (task instanceof ForkJoinTask<?>) // avoid re-wrap
|
||||
job = (ForkJoinTask<?>) task;
|
||||
else
|
||||
job = ForkJoinTask.adapt(task, null);
|
||||
doSubmit(job);
|
||||
forkOrSubmit(job);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1390,7 +1459,9 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
|
||||
doSubmit(task);
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
forkOrSubmit(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@ -1400,8 +1471,10 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public <T> ForkJoinTask<T> submit(Callable<T> task) {
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
ForkJoinTask<T> job = ForkJoinTask.adapt(task);
|
||||
doSubmit(job);
|
||||
forkOrSubmit(job);
|
||||
return job;
|
||||
}
|
||||
|
||||
@ -1411,8 +1484,10 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public <T> ForkJoinTask<T> submit(Runnable task, T result) {
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
ForkJoinTask<T> job = ForkJoinTask.adapt(task, result);
|
||||
doSubmit(job);
|
||||
forkOrSubmit(job);
|
||||
return job;
|
||||
}
|
||||
|
||||
@ -1422,12 +1497,14 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* scheduled for execution
|
||||
*/
|
||||
public ForkJoinTask<?> submit(Runnable task) {
|
||||
if (task == null)
|
||||
throw new NullPointerException();
|
||||
ForkJoinTask<?> job;
|
||||
if (task instanceof ForkJoinTask<?>) // avoid re-wrap
|
||||
job = (ForkJoinTask<?>) task;
|
||||
else
|
||||
job = ForkJoinTask.adapt(task, null);
|
||||
doSubmit(job);
|
||||
forkOrSubmit(job);
|
||||
return job;
|
||||
}
|
||||
|
||||
@ -1725,8 +1802,11 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
* commenced but not yet completed. This method may be useful for
|
||||
* debugging. A return of {@code true} reported a sufficient
|
||||
* period after shutdown may indicate that submitted tasks have
|
||||
* ignored or suppressed interruption, causing this executor not
|
||||
* to properly terminate.
|
||||
* ignored or suppressed interruption, or are waiting for IO,
|
||||
* causing this executor not to properly terminate. (See the
|
||||
* advisory notes for class {@link ForkJoinTask} stating that
|
||||
* tasks should not normally entail blocking operations. But if
|
||||
* they do, they must abort them on interrupt.)
|
||||
*
|
||||
* @return {@code true} if terminating but not yet terminated
|
||||
*/
|
||||
@ -1764,10 +1844,11 @@ public class ForkJoinPool extends AbstractExecutorService {
|
||||
public boolean awaitTermination(long timeout, TimeUnit unit)
|
||||
throws InterruptedException {
|
||||
try {
|
||||
return termination.awaitAdvanceInterruptibly(0, timeout, unit) > 0;
|
||||
termination.awaitAdvanceInterruptibly(0, timeout, unit);
|
||||
} catch (TimeoutException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,6 +42,16 @@ import java.util.List;
|
||||
import java.util.RandomAccess;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.RunnableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Abstract base class for tasks that run within a {@link ForkJoinPool}.
|
||||
@ -129,6 +139,16 @@ import java.util.WeakHashMap;
|
||||
* result in exceptions or errors, possibly including
|
||||
* {@code ClassCastException}.
|
||||
*
|
||||
* <p>Method {@link #join} and its variants are appropriate for use
|
||||
* only when completion dependencies are acyclic; that is, the
|
||||
* parallel computation can be described as a directed acyclic graph
|
||||
* (DAG). Otherwise, executions may encounter a form of deadlock as
|
||||
* tasks cyclically wait for each other. However, this framework
|
||||
* supports other methods and techniques (for example the use of
|
||||
* {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
|
||||
* may be of use in constructing custom subclasses for problems that
|
||||
* are not statically structured as DAGs.
|
||||
*
|
||||
* <p>Most base support methods are {@code final}, to prevent
|
||||
* overriding of implementations that are intrinsically tied to the
|
||||
* underlying lightweight task scheduling framework. Developers
|
||||
@ -143,9 +163,10 @@ import java.util.WeakHashMap;
|
||||
* computation. Large tasks should be split into smaller subtasks,
|
||||
* usually via recursive decomposition. As a very rough rule of thumb,
|
||||
* a task should perform more than 100 and less than 10000 basic
|
||||
* computational steps. If tasks are too big, then parallelism cannot
|
||||
* improve throughput. If too small, then memory and internal task
|
||||
* maintenance overhead may overwhelm processing.
|
||||
* computational steps, and should avoid indefinite looping. If tasks
|
||||
* are too big, then parallelism cannot improve throughput. If too
|
||||
* small, then memory and internal task maintenance overhead may
|
||||
* overwhelm processing.
|
||||
*
|
||||
* <p>This class provides {@code adapt} methods for {@link Runnable}
|
||||
* and {@link Callable}, that may be of use when mixing execution of
|
||||
@ -241,66 +262,84 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
setCompletion(EXCEPTIONAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks a worker thread until completion. Called only by
|
||||
* pool. Currently unused -- pool-based waits use timeout
|
||||
* version below.
|
||||
*/
|
||||
final void internalAwaitDone() {
|
||||
int s; // the odd construction reduces lock bias effects
|
||||
while ((s = status) >= 0) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
|
||||
wait();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
cancelIfTerminating();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks a worker thread until completed or timed out. Called
|
||||
* only by pool.
|
||||
*
|
||||
* @return status on exit
|
||||
*/
|
||||
final int internalAwaitDone(long millis) {
|
||||
int s;
|
||||
if ((s = status) >= 0) {
|
||||
try {
|
||||
final void internalAwaitDone(long millis, int nanos) {
|
||||
int s = status;
|
||||
if ((s == 0 &&
|
||||
UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL)) ||
|
||||
s > 0) {
|
||||
try { // the odd construction reduces lock bias effects
|
||||
synchronized (this) {
|
||||
if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
|
||||
wait(millis, 0);
|
||||
if (status > 0)
|
||||
wait(millis, nanos);
|
||||
else
|
||||
notifyAll();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
cancelIfTerminating();
|
||||
}
|
||||
s = status;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks a non-worker-thread until completion.
|
||||
*/
|
||||
private void externalAwaitDone() {
|
||||
int s;
|
||||
while ((s = status) >= 0) {
|
||||
if (status >= 0) {
|
||||
boolean interrupted = false;
|
||||
synchronized (this) {
|
||||
if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)){
|
||||
boolean interrupted = false;
|
||||
while (status >= 0) {
|
||||
for (;;) {
|
||||
int s = status;
|
||||
if (s == 0)
|
||||
UNSAFE.compareAndSwapInt(this, statusOffset,
|
||||
0, SIGNAL);
|
||||
else if (s < 0) {
|
||||
notifyAll();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException ie) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (interrupted)
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks a non-worker-thread until completion or interruption or timeout.
|
||||
*/
|
||||
private void externalInterruptibleAwaitDone(boolean timed, long nanos)
|
||||
throws InterruptedException {
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
if (status >= 0) {
|
||||
long startTime = timed ? System.nanoTime() : 0L;
|
||||
synchronized (this) {
|
||||
for (;;) {
|
||||
long nt;
|
||||
int s = status;
|
||||
if (s == 0)
|
||||
UNSAFE.compareAndSwapInt(this, statusOffset,
|
||||
0, SIGNAL);
|
||||
else if (s < 0) {
|
||||
notifyAll();
|
||||
break;
|
||||
}
|
||||
else if (!timed)
|
||||
wait();
|
||||
else if ((nt = nanos - (System.nanoTime()-startTime)) > 0L)
|
||||
wait(nt / 1000000, (int)(nt % 1000000));
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -335,7 +374,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* #isDone} returning {@code true}.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -349,10 +388,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result of the computation when it {@link #isDone is done}.
|
||||
* This method differs from {@link #get()} in that
|
||||
* Returns the result of the computation when it {@link #isDone is
|
||||
* done}. This method differs from {@link #get()} in that
|
||||
* abnormal completion results in {@code RuntimeException} or
|
||||
* {@code Error}, not {@code ExecutionException}.
|
||||
* {@code Error}, not {@code ExecutionException}, and that
|
||||
* interrupts of the calling thread do <em>not</em> cause the
|
||||
* method to abruptly return by throwing {@code
|
||||
* InterruptedException}.
|
||||
*
|
||||
* @return the computed result
|
||||
*/
|
||||
@ -394,7 +436,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* unprocessed.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -422,7 +464,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* normally or exceptionally, or left unprocessed.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -477,7 +519,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* unprocessed.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -529,25 +571,28 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
|
||||
/**
|
||||
* Attempts to cancel execution of this task. This attempt will
|
||||
* fail if the task has already completed, has already been
|
||||
* cancelled, or could not be cancelled for some other reason. If
|
||||
* successful, and this task has not started when cancel is
|
||||
* called, execution of this task is suppressed, {@link
|
||||
* #isCancelled} will report true, and {@link #join} will result
|
||||
* in a {@code CancellationException} being thrown.
|
||||
* fail if the task has already completed or could not be
|
||||
* cancelled for some other reason. If successful, and this task
|
||||
* has not started when {@code cancel} is called, execution of
|
||||
* this task is suppressed. After this method returns
|
||||
* successfully, unless there is an intervening call to {@link
|
||||
* #reinitialize}, subsequent calls to {@link #isCancelled},
|
||||
* {@link #isDone}, and {@code cancel} will return {@code true}
|
||||
* and calls to {@link #join} and related methods will result in
|
||||
* {@code CancellationException}.
|
||||
*
|
||||
* <p>This method may be overridden in subclasses, but if so, must
|
||||
* still ensure that these minimal properties hold. In particular,
|
||||
* the {@code cancel} method itself must not throw exceptions.
|
||||
* still ensure that these properties hold. In particular, the
|
||||
* {@code cancel} method itself must not throw exceptions.
|
||||
*
|
||||
* <p>This method is designed to be invoked by <em>other</em>
|
||||
* tasks. To terminate the current task, you can just return or
|
||||
* throw an unchecked exception from its computation method, or
|
||||
* invoke {@link #completeExceptionally}.
|
||||
*
|
||||
* @param mayInterruptIfRunning this value is ignored in the
|
||||
* default implementation because tasks are not
|
||||
* cancelled via interruption
|
||||
* @param mayInterruptIfRunning this value has no effect in the
|
||||
* default implementation because interrupts are not used to
|
||||
* control cancellation.
|
||||
*
|
||||
* @return {@code true} if this task is now cancelled
|
||||
*/
|
||||
@ -681,23 +726,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* member of a ForkJoinPool and was interrupted while waiting
|
||||
*/
|
||||
public final V get() throws InterruptedException, ExecutionException {
|
||||
int s;
|
||||
if (Thread.currentThread() instanceof ForkJoinWorkerThread) {
|
||||
Thread t = Thread.currentThread();
|
||||
if (t instanceof ForkJoinWorkerThread)
|
||||
quietlyJoin();
|
||||
s = status;
|
||||
}
|
||||
else {
|
||||
while ((s = status) >= 0) {
|
||||
synchronized (this) { // interruptible form of awaitDone
|
||||
if (UNSAFE.compareAndSwapInt(this, statusOffset,
|
||||
s, SIGNAL)) {
|
||||
while (status >= 0)
|
||||
wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s < NORMAL) {
|
||||
else
|
||||
externalInterruptibleAwaitDone(false, 0L);
|
||||
int s = status;
|
||||
if (s != NORMAL) {
|
||||
Throwable ex;
|
||||
if (s == CANCELLED)
|
||||
throw new CancellationException();
|
||||
@ -723,72 +758,18 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
*/
|
||||
public final V get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
Thread t = Thread.currentThread();
|
||||
ForkJoinPool pool;
|
||||
if (t instanceof ForkJoinWorkerThread) {
|
||||
ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
|
||||
if (status >= 0 && w.unpushTask(this))
|
||||
quietlyExec();
|
||||
pool = w.pool;
|
||||
}
|
||||
else
|
||||
pool = null;
|
||||
/*
|
||||
* Timed wait loop intermixes cases for FJ (pool != null) and
|
||||
* non FJ threads. For FJ, decrement pool count but don't try
|
||||
* for replacement; increment count on completion. For non-FJ,
|
||||
* deal with interrupts. This is messy, but a little less so
|
||||
* than is splitting the FJ and nonFJ cases.
|
||||
*/
|
||||
boolean interrupted = false;
|
||||
boolean dec = false; // true if pool count decremented
|
||||
long nanos = unit.toNanos(timeout);
|
||||
for (;;) {
|
||||
if (pool == null && Thread.interrupted()) {
|
||||
interrupted = true;
|
||||
break;
|
||||
}
|
||||
int s = status;
|
||||
if (s < 0)
|
||||
break;
|
||||
if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)) {
|
||||
long startTime = System.nanoTime();
|
||||
long nt; // wait time
|
||||
while (status >= 0 &&
|
||||
(nt = nanos - (System.nanoTime() - startTime)) > 0) {
|
||||
if (pool != null && !dec)
|
||||
dec = pool.tryDecrementRunningCount();
|
||||
else {
|
||||
long ms = nt / 1000000;
|
||||
int ns = (int) (nt % 1000000);
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (status >= 0)
|
||||
wait(ms, ns);
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
if (pool != null)
|
||||
cancelIfTerminating();
|
||||
else {
|
||||
interrupted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pool != null && dec)
|
||||
pool.incrementRunningCount();
|
||||
if (interrupted)
|
||||
throw new InterruptedException();
|
||||
int es = status;
|
||||
if (es != NORMAL) {
|
||||
Thread t = Thread.currentThread();
|
||||
if (t instanceof ForkJoinWorkerThread)
|
||||
((ForkJoinWorkerThread)t).joinTask(this, true, nanos);
|
||||
else
|
||||
externalInterruptibleAwaitDone(true, nanos);
|
||||
int s = status;
|
||||
if (s != NORMAL) {
|
||||
Throwable ex;
|
||||
if (es == CANCELLED)
|
||||
if (s == CANCELLED)
|
||||
throw new CancellationException();
|
||||
if (es == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
|
||||
if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
|
||||
throw new ExecutionException(ex);
|
||||
throw new TimeoutException();
|
||||
}
|
||||
@ -819,7 +800,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
return;
|
||||
}
|
||||
}
|
||||
w.joinTask(this);
|
||||
w.joinTask(this, false, 0L);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -855,7 +836,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* processed.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -874,6 +855,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* under any other usage conditions are not guaranteed.
|
||||
* This method may be useful when executing
|
||||
* pre-constructed trees of subtasks in loops.
|
||||
*
|
||||
* <p>Upon completion of this method, {@code isDone()} reports
|
||||
* {@code false}, and {@code getException()} reports {@code
|
||||
* null}. However, the value returned by {@code getRawResult} is
|
||||
* unaffected. To clear this value, you can invoke {@code
|
||||
* setRawResult(null)}.
|
||||
*/
|
||||
public void reinitialize() {
|
||||
if (status == EXCEPTIONAL)
|
||||
@ -895,11 +882,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the current thread is executing as a
|
||||
* ForkJoinPool computation.
|
||||
* Returns {@code true} if the current thread is a {@link
|
||||
* ForkJoinWorkerThread} executing as a ForkJoinPool computation.
|
||||
*
|
||||
* @return {@code true} if the current thread is executing as a
|
||||
* ForkJoinPool computation, or false otherwise
|
||||
* @return {@code true} if the current thread is a {@link
|
||||
* ForkJoinWorkerThread} executing as a ForkJoinPool computation,
|
||||
* or {@code false} otherwise
|
||||
*/
|
||||
public static boolean inForkJoinPool() {
|
||||
return Thread.currentThread() instanceof ForkJoinWorkerThread;
|
||||
@ -914,7 +902,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* were not, stolen.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -933,7 +921,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* fork other tasks.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -956,7 +944,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* exceeded.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -1014,7 +1002,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* otherwise.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -1033,7 +1021,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* be useful otherwise.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
@ -1056,7 +1044,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
|
||||
* otherwise.
|
||||
*
|
||||
* <p>This method may be invoked only from within {@code
|
||||
* ForkJoinTask} computations (as may be determined using method
|
||||
* ForkJoinPool} computations (as may be determined using method
|
||||
* {@link #inForkJoinPool}). Attempts to invoke in other contexts
|
||||
* result in exceptions or errors, possibly including {@code
|
||||
* ClassCastException}.
|
||||
|
@ -38,16 +38,18 @@ package java.util.concurrent;
|
||||
import java.util.Random;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
/**
|
||||
* A thread managed by a {@link ForkJoinPool}. This class is
|
||||
* subclassable solely for the sake of adding functionality -- there
|
||||
* are no overridable methods dealing with scheduling or execution.
|
||||
* However, you can override initialization and termination methods
|
||||
* surrounding the main task processing loop. If you do create such a
|
||||
* subclass, you will also need to supply a custom {@link
|
||||
* ForkJoinPool.ForkJoinWorkerThreadFactory} to use it in a {@code
|
||||
* ForkJoinPool}.
|
||||
* A thread managed by a {@link ForkJoinPool}, which executes
|
||||
* {@link ForkJoinTask}s.
|
||||
* This class is subclassable solely for the sake of adding
|
||||
* functionality -- there are no overridable methods dealing with
|
||||
* scheduling or execution. However, you can override initialization
|
||||
* and termination methods surrounding the main task processing loop.
|
||||
* If you do create such a subclass, you will also need to supply a
|
||||
* custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to use it
|
||||
* in a {@code ForkJoinPool}.
|
||||
*
|
||||
* @since 1.7
|
||||
* @author Doug Lea
|
||||
@ -376,7 +378,7 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
/**
|
||||
* Initializes internal state after construction but before
|
||||
* processing any tasks. If you override this method, you must
|
||||
* invoke @code{super.onStart()} at the beginning of the method.
|
||||
* invoke {@code super.onStart()} at the beginning of the method.
|
||||
* Initialization requires care: Most fields must have legal
|
||||
* default values, to ensure that attempted accesses from other
|
||||
* threads work correctly even before this thread starts
|
||||
@ -384,7 +386,7 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
*/
|
||||
protected void onStart() {
|
||||
int rs = seedGenerator.nextInt();
|
||||
seed = rs == 0? 1 : rs; // seed must be nonzero
|
||||
seed = (rs == 0) ? 1 : rs; // seed must be nonzero
|
||||
|
||||
// Allocate name string and arrays in this thread
|
||||
String pid = Integer.toString(pool.getPoolNumber());
|
||||
@ -426,7 +428,7 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
/**
|
||||
* This method is required to be public, but should never be
|
||||
* called explicitly. It performs the main run loop to execute
|
||||
* ForkJoinTasks.
|
||||
* {@link ForkJoinTask}s.
|
||||
*/
|
||||
public void run() {
|
||||
Throwable exception = null;
|
||||
@ -628,6 +630,19 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
if (t == null) // lost to stealer
|
||||
break;
|
||||
if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
|
||||
/*
|
||||
* Note: here and in related methods, as a
|
||||
* performance (not correctness) issue, we'd like
|
||||
* to encourage compiler not to arbitrarily
|
||||
* postpone setting sp after successful CAS.
|
||||
* Currently there is no intrinsic for arranging
|
||||
* this, but using Unsafe putOrderedInt may be a
|
||||
* preferable strategy on some compilers even
|
||||
* though its main effect is a pre-, not post-
|
||||
* fence. To simplify possible changes, the option
|
||||
* is left in comments next to the associated
|
||||
* assignments.
|
||||
*/
|
||||
sp = s; // putOrderedInt may encourage more timely write
|
||||
// UNSAFE.putOrderedInt(this, spOffset, s);
|
||||
return t;
|
||||
@ -777,10 +792,10 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
// Run State management
|
||||
|
||||
// status check methods used mainly by ForkJoinPool
|
||||
final boolean isRunning() { return runState == 0; }
|
||||
final boolean isTerminated() { return (runState & TERMINATED) != 0; }
|
||||
final boolean isSuspended() { return (runState & SUSPENDED) != 0; }
|
||||
final boolean isTrimmed() { return (runState & TRIMMED) != 0; }
|
||||
final boolean isRunning() { return runState == 0; }
|
||||
final boolean isTerminated() { return (runState & TERMINATED) != 0; }
|
||||
final boolean isSuspended() { return (runState & SUSPENDED) != 0; }
|
||||
final boolean isTrimmed() { return (runState & TRIMMED) != 0; }
|
||||
|
||||
final boolean isTerminating() {
|
||||
if ((runState & TERMINATING) != 0)
|
||||
@ -884,8 +899,7 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
*/
|
||||
final void cancelTasks() {
|
||||
ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks
|
||||
if (cj != null) {
|
||||
currentJoin = null;
|
||||
if (cj != null && cj.status >= 0) {
|
||||
cj.cancelIgnoringExceptions();
|
||||
try {
|
||||
this.interrupt(); // awaken wait
|
||||
@ -893,10 +907,8 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
}
|
||||
}
|
||||
ForkJoinTask<?> cs = currentSteal;
|
||||
if (cs != null) {
|
||||
currentSteal = null;
|
||||
if (cs != null && cs.status >= 0)
|
||||
cs.cancelIgnoringExceptions();
|
||||
}
|
||||
while (base != sp) {
|
||||
ForkJoinTask<?> t = deqTask();
|
||||
if (t != null)
|
||||
@ -959,57 +971,23 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
* Possibly runs some tasks and/or blocks, until task is done.
|
||||
*
|
||||
* @param joinMe the task to join
|
||||
* @param timed true if use timed wait
|
||||
* @param nanos wait time if timed
|
||||
*/
|
||||
final void joinTask(ForkJoinTask<?> joinMe) {
|
||||
final void joinTask(ForkJoinTask<?> joinMe, boolean timed, long nanos) {
|
||||
// currentJoin only written by this thread; only need ordered store
|
||||
ForkJoinTask<?> prevJoin = currentJoin;
|
||||
UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe);
|
||||
if (sp != base)
|
||||
localHelpJoinTask(joinMe);
|
||||
if (joinMe.status >= 0)
|
||||
pool.awaitJoin(joinMe, this);
|
||||
pool.awaitJoin(joinMe, this, timed, nanos);
|
||||
UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run tasks in local queue until given task is done.
|
||||
*
|
||||
* @param joinMe the task to join
|
||||
*/
|
||||
private void localHelpJoinTask(ForkJoinTask<?> joinMe) {
|
||||
int s;
|
||||
ForkJoinTask<?>[] q;
|
||||
while (joinMe.status >= 0 && (s = sp) != base && (q = queue) != null) {
|
||||
int i = (q.length - 1) & --s;
|
||||
long u = (i << qShift) + qBase; // raw offset
|
||||
ForkJoinTask<?> t = q[i];
|
||||
if (t == null) // lost to a stealer
|
||||
break;
|
||||
if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
|
||||
/*
|
||||
* This recheck (and similarly in helpJoinTask)
|
||||
* handles cases where joinMe is independently
|
||||
* cancelled or forced even though there is other work
|
||||
* available. Back out of the pop by putting t back
|
||||
* into slot before we commit by writing sp.
|
||||
*/
|
||||
if (joinMe.status < 0) {
|
||||
UNSAFE.putObjectVolatile(q, u, t);
|
||||
break;
|
||||
}
|
||||
sp = s;
|
||||
// UNSAFE.putOrderedInt(this, spOffset, s);
|
||||
t.quietlyExec();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unless terminating, tries to locate and help perform tasks for
|
||||
* a stealer of the given task, or in turn one of its stealers.
|
||||
* Traces currentSteal->currentJoin links looking for a thread
|
||||
* working on a descendant of the given task and with a non-empty
|
||||
* queue to steal back and execute tasks from.
|
||||
* Tries to locate and help perform tasks for a stealer of the
|
||||
* given task, or in turn one of its stealers. Traces
|
||||
* currentSteal->currentJoin links looking for a thread working on
|
||||
* a descendant of the given task and with a non-empty queue to
|
||||
* steal back and execute tasks from.
|
||||
*
|
||||
* The implementation is very branchy to cope with potential
|
||||
* inconsistencies or loops encountering chains that are stale,
|
||||
@ -1019,77 +997,127 @@ public class ForkJoinWorkerThread extends Thread {
|
||||
* don't work out.
|
||||
*
|
||||
* @param joinMe the task to join
|
||||
* @param running if false, then must update pool count upon
|
||||
* running a task
|
||||
* @return value of running on exit
|
||||
*/
|
||||
final void helpJoinTask(ForkJoinTask<?> joinMe) {
|
||||
ForkJoinWorkerThread[] ws;
|
||||
int n;
|
||||
if (joinMe.status < 0) // already done
|
||||
return;
|
||||
if ((runState & TERMINATING) != 0) { // cancel if shutting down
|
||||
joinMe.cancelIgnoringExceptions();
|
||||
return;
|
||||
final boolean helpJoinTask(ForkJoinTask<?> joinMe, boolean running) {
|
||||
/*
|
||||
* Initial checks to (1) abort if terminating; (2) clean out
|
||||
* old cancelled tasks from local queue; (3) if joinMe is next
|
||||
* task, run it; (4) omit scan if local queue nonempty (since
|
||||
* it may contain non-descendents of joinMe).
|
||||
*/
|
||||
ForkJoinPool p = pool;
|
||||
for (;;) {
|
||||
ForkJoinTask<?>[] q;
|
||||
int s;
|
||||
if (joinMe.status < 0)
|
||||
return running;
|
||||
else if ((runState & TERMINATING) != 0) {
|
||||
joinMe.cancelIgnoringExceptions();
|
||||
return running;
|
||||
}
|
||||
else if ((s = sp) == base || (q = queue) == null)
|
||||
break; // queue empty
|
||||
else {
|
||||
int i = (q.length - 1) & --s;
|
||||
long u = (i << qShift) + qBase; // raw offset
|
||||
ForkJoinTask<?> t = q[i];
|
||||
if (t == null)
|
||||
break; // lost to a stealer
|
||||
else if (t != joinMe && t.status >= 0)
|
||||
return running; // cannot safely help
|
||||
else if ((running ||
|
||||
(running = p.tryIncrementRunningCount())) &&
|
||||
UNSAFE.compareAndSwapObject(q, u, t, null)) {
|
||||
sp = s; // putOrderedInt may encourage more timely write
|
||||
// UNSAFE.putOrderedInt(this, spOffset, s);
|
||||
t.quietlyExec();
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((ws = pool.workers) == null || (n = ws.length) <= 1)
|
||||
return; // need at least 2 workers
|
||||
|
||||
ForkJoinTask<?> task = joinMe; // base of chain
|
||||
ForkJoinWorkerThread thread = this; // thread with stolen task
|
||||
for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length
|
||||
// Try to find v, the stealer of task, by first using hint
|
||||
ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)];
|
||||
if (v == null || v.currentSteal != task) {
|
||||
for (int j = 0; ; ++j) { // search array
|
||||
if (j < n) {
|
||||
ForkJoinTask<?> vs;
|
||||
if ((v = ws[j]) != null &&
|
||||
(vs = v.currentSteal) != null) {
|
||||
if (joinMe.status < 0 || task.status < 0)
|
||||
return; // stale or done
|
||||
if (vs == task) {
|
||||
thread.stealHint = j;
|
||||
break; // save hint for next time
|
||||
int n; // worker array size
|
||||
ForkJoinWorkerThread[] ws = p.workers;
|
||||
if (ws != null && (n = ws.length) > 1) { // need at least 2 workers
|
||||
ForkJoinTask<?> task = joinMe; // base of chain
|
||||
ForkJoinWorkerThread thread = this; // thread with stolen task
|
||||
|
||||
outer:for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length
|
||||
// Try to find v, the stealer of task, by first using hint
|
||||
ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)];
|
||||
if (v == null || v.currentSteal != task) {
|
||||
for (int j = 0; ; ++j) { // search array
|
||||
if (j < n) {
|
||||
ForkJoinTask<?> vs;
|
||||
if ((v = ws[j]) != null &&
|
||||
(vs = v.currentSteal) != null) {
|
||||
if (joinMe.status < 0)
|
||||
break outer;
|
||||
if (vs == task) {
|
||||
if (task.status < 0)
|
||||
break outer; // stale
|
||||
thread.stealHint = j;
|
||||
break; // save hint for next time
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
break outer; // no stealer
|
||||
}
|
||||
else
|
||||
return; // no stealer
|
||||
}
|
||||
}
|
||||
for (;;) { // Try to help v, using specialized form of deqTask
|
||||
if (joinMe.status < 0)
|
||||
return;
|
||||
int b = v.base;
|
||||
ForkJoinTask<?>[] q = v.queue;
|
||||
if (b == v.sp || q == null)
|
||||
break;
|
||||
int i = (q.length - 1) & b;
|
||||
long u = (i << qShift) + qBase;
|
||||
ForkJoinTask<?> t = q[i];
|
||||
int pid = poolIndex;
|
||||
ForkJoinTask<?> ps = currentSteal;
|
||||
if (task.status < 0)
|
||||
return; // stale or done
|
||||
if (t != null && v.base == b++ &&
|
||||
UNSAFE.compareAndSwapObject(q, u, t, null)) {
|
||||
if (joinMe.status < 0) {
|
||||
UNSAFE.putObjectVolatile(q, u, t);
|
||||
return; // back out on cancel
|
||||
|
||||
// Try to help v, using specialized form of deqTask
|
||||
for (;;) {
|
||||
if (joinMe.status < 0)
|
||||
break outer;
|
||||
int b = v.base;
|
||||
ForkJoinTask<?>[] q = v.queue;
|
||||
if (b == v.sp || q == null)
|
||||
break; // empty
|
||||
int i = (q.length - 1) & b;
|
||||
long u = (i << qShift) + qBase;
|
||||
ForkJoinTask<?> t = q[i];
|
||||
if (task.status < 0)
|
||||
break outer; // stale
|
||||
if (t != null &&
|
||||
(running ||
|
||||
(running = p.tryIncrementRunningCount())) &&
|
||||
v.base == b++ &&
|
||||
UNSAFE.compareAndSwapObject(q, u, t, null)) {
|
||||
if (t != joinMe && joinMe.status < 0) {
|
||||
UNSAFE.putObjectVolatile(q, u, t);
|
||||
break outer; // joinMe cancelled; back out
|
||||
}
|
||||
v.base = b;
|
||||
if (t.status >= 0) {
|
||||
ForkJoinTask<?> ps = currentSteal;
|
||||
int pid = poolIndex;
|
||||
v.stealHint = pid;
|
||||
UNSAFE.putOrderedObject(this,
|
||||
currentStealOffset, t);
|
||||
t.quietlyExec();
|
||||
UNSAFE.putOrderedObject(this,
|
||||
currentStealOffset, ps);
|
||||
}
|
||||
}
|
||||
else if ((runState & TERMINATING) != 0) {
|
||||
joinMe.cancelIgnoringExceptions();
|
||||
break outer;
|
||||
}
|
||||
v.base = b;
|
||||
v.stealHint = pid;
|
||||
UNSAFE.putOrderedObject(this, currentStealOffset, t);
|
||||
t.quietlyExec();
|
||||
UNSAFE.putOrderedObject(this, currentStealOffset, ps);
|
||||
}
|
||||
|
||||
// Try to descend to find v's stealer
|
||||
ForkJoinTask<?> next = v.currentJoin;
|
||||
if (task.status < 0 || next == null || next == task ||
|
||||
joinMe.status < 0)
|
||||
break; // done, stale, dead-end, or cyclic
|
||||
task = next;
|
||||
thread = v;
|
||||
}
|
||||
// Try to descend to find v's stealer
|
||||
ForkJoinTask<?> next = v.currentJoin;
|
||||
if (task.status < 0 || next == null || next == task ||
|
||||
joinMe.status < 0)
|
||||
return;
|
||||
task = next;
|
||||
thread = v;
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1029,6 +1029,8 @@ public class LinkedBlockingDeque<E>
|
||||
* elements as they existed upon construction of the iterator, and
|
||||
* may (but is not guaranteed to) reflect any modifications
|
||||
* subsequent to construction.
|
||||
*
|
||||
* @return an iterator over the elements in this deque in reverse order
|
||||
*/
|
||||
public Iterator<E> descendingIterator() {
|
||||
return new DescendingItr();
|
||||
|
@ -189,14 +189,14 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a node and links it at end of queue.
|
||||
* Links node at end of queue.
|
||||
*
|
||||
* @param x the item
|
||||
* @param node the node
|
||||
*/
|
||||
private void enqueue(E x) {
|
||||
private void enqueue(Node<E> node) {
|
||||
// assert putLock.isHeldByCurrentThread();
|
||||
// assert last.next == null;
|
||||
last = last.next = new Node<E>(x);
|
||||
last = last.next = node;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -282,7 +282,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
throw new NullPointerException();
|
||||
if (n == capacity)
|
||||
throw new IllegalStateException("Queue full");
|
||||
enqueue(e);
|
||||
enqueue(new Node<E>(e));
|
||||
++n;
|
||||
}
|
||||
count.set(n);
|
||||
@ -332,6 +332,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
// Note: convention in all put/take/etc is to preset local var
|
||||
// holding count negative to indicate failure unless set.
|
||||
int c = -1;
|
||||
Node<E> node = new Node(e);
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
final AtomicInteger count = this.count;
|
||||
putLock.lockInterruptibly();
|
||||
@ -347,7 +348,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
while (count.get() == capacity) {
|
||||
notFull.await();
|
||||
}
|
||||
enqueue(e);
|
||||
enqueue(node);
|
||||
c = count.getAndIncrement();
|
||||
if (c + 1 < capacity)
|
||||
notFull.signal();
|
||||
@ -382,7 +383,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
return false;
|
||||
nanos = notFull.awaitNanos(nanos);
|
||||
}
|
||||
enqueue(e);
|
||||
enqueue(new Node<E>(e));
|
||||
c = count.getAndIncrement();
|
||||
if (c + 1 < capacity)
|
||||
notFull.signal();
|
||||
@ -411,11 +412,12 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
if (count.get() == capacity)
|
||||
return false;
|
||||
int c = -1;
|
||||
Node<E> node = new Node(e);
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
putLock.lock();
|
||||
try {
|
||||
if (count.get() < capacity) {
|
||||
enqueue(e);
|
||||
enqueue(node);
|
||||
c = count.getAndIncrement();
|
||||
if (c + 1 < capacity)
|
||||
notFull.signal();
|
||||
@ -559,6 +561,27 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this queue contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this queue contains
|
||||
* at least one element {@code e} such that {@code o.equals(e)}.
|
||||
*
|
||||
* @param o object to be checked for containment in this queue
|
||||
* @return {@code true} if this queue contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
if (o == null) return false;
|
||||
fullyLock();
|
||||
try {
|
||||
for (Node<E> p = head.next; p != null; p = p.next)
|
||||
if (o.equals(p.item))
|
||||
return true;
|
||||
return false;
|
||||
} finally {
|
||||
fullyUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all of the elements in this queue, in
|
||||
* proper sequence.
|
||||
@ -645,7 +668,20 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
public String toString() {
|
||||
fullyLock();
|
||||
try {
|
||||
return super.toString();
|
||||
Node<E> p = head.next;
|
||||
if (p == null)
|
||||
return "[]";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (;;) {
|
||||
E e = p.item;
|
||||
sb.append(e == this ? "(this Collection)" : e);
|
||||
p = p.next;
|
||||
if (p == null)
|
||||
return sb.append(']').toString();
|
||||
sb.append(',').append(' ');
|
||||
}
|
||||
} finally {
|
||||
fullyUnlock();
|
||||
}
|
||||
@ -727,12 +763,14 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Returns an iterator over the elements in this queue in proper sequence.
|
||||
* The returned {@code Iterator} is a "weakly consistent" iterator that
|
||||
* The elements will be returned in order from first (head) to last (tail).
|
||||
*
|
||||
* <p>The returned iterator is a "weakly consistent" iterator that
|
||||
* will never throw {@link java.util.ConcurrentModificationException
|
||||
* ConcurrentModificationException},
|
||||
* and guarantees to traverse elements as they existed upon
|
||||
* construction of the iterator, and may (but is not guaranteed to)
|
||||
* reflect any modifications subsequent to construction.
|
||||
* ConcurrentModificationException}, and guarantees to traverse
|
||||
* elements as they existed upon construction of the iterator, and
|
||||
* may (but is not guaranteed to) reflect any modifications
|
||||
* subsequent to construction.
|
||||
*
|
||||
* @return an iterator over the elements in this queue in proper sequence
|
||||
*/
|
||||
|
@ -37,10 +37,10 @@ package java.util.concurrent;
|
||||
|
||||
import java.util.AbstractQueue;
|
||||
import java.util.Collection;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
/**
|
||||
@ -450,7 +450,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
final boolean casItem(Object cmp, Object val) {
|
||||
// assert cmp == null || cmp.getClass() != Node.class;
|
||||
// assert cmp == null || cmp.getClass() != Node.class;
|
||||
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
|
||||
}
|
||||
|
||||
@ -516,7 +516,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* Tries to artificially match a data node -- used by remove.
|
||||
*/
|
||||
final boolean tryMatchData() {
|
||||
// assert isData;
|
||||
// assert isData;
|
||||
Object x = item;
|
||||
if (x != null && x != this && casItem(x, null)) {
|
||||
LockSupport.unpark(waiter);
|
||||
@ -569,7 +569,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <E> E cast(Object item) {
|
||||
// assert item == null || item.getClass() != Node.class;
|
||||
// assert item == null || item.getClass() != Node.class;
|
||||
return (E) item;
|
||||
}
|
||||
|
||||
@ -588,7 +588,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
throw new NullPointerException();
|
||||
Node s = null; // the node to append, if needed
|
||||
|
||||
retry: for (;;) { // restart on append race
|
||||
retry:
|
||||
for (;;) { // restart on append race
|
||||
|
||||
for (Node h = head, p = h; p != null;) { // find & match first node
|
||||
boolean isData = p.isData;
|
||||
@ -599,7 +600,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
if (p.casItem(item, e)) { // match
|
||||
for (Node q = p; q != h;) {
|
||||
Node n = q.next; // update by 2 unless singleton
|
||||
if (head == h && casHead(h, n == null? q : n)) {
|
||||
if (head == h && casHead(h, n == null ? q : n)) {
|
||||
h.forgetNext();
|
||||
break;
|
||||
} // advance and retry
|
||||
@ -684,7 +685,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
for (;;) {
|
||||
Object item = s.item;
|
||||
if (item != e) { // matched
|
||||
// assert item != s;
|
||||
// assert item != s;
|
||||
s.forgetContents(); // avoid garbage
|
||||
return this.<E>cast(item);
|
||||
}
|
||||
@ -809,22 +810,61 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* Moves to next node after prev, or first node if prev null.
|
||||
*/
|
||||
private void advance(Node prev) {
|
||||
lastPred = lastRet;
|
||||
lastRet = prev;
|
||||
for (Node p = (prev == null) ? head : succ(prev);
|
||||
p != null; p = succ(p)) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p) {
|
||||
nextItem = LinkedTransferQueue.this.<E>cast(item);
|
||||
nextNode = p;
|
||||
/*
|
||||
* To track and avoid buildup of deleted nodes in the face
|
||||
* of calls to both Queue.remove and Itr.remove, we must
|
||||
* include variants of unsplice and sweep upon each
|
||||
* advance: Upon Itr.remove, we may need to catch up links
|
||||
* from lastPred, and upon other removes, we might need to
|
||||
* skip ahead from stale nodes and unsplice deleted ones
|
||||
* found while advancing.
|
||||
*/
|
||||
|
||||
Node r, b; // reset lastPred upon possible deletion of lastRet
|
||||
if ((r = lastRet) != null && !r.isMatched())
|
||||
lastPred = r; // next lastPred is old lastRet
|
||||
else if ((b = lastPred) == null || b.isMatched())
|
||||
lastPred = null; // at start of list
|
||||
else {
|
||||
Node s, n; // help with removal of lastPred.next
|
||||
while ((s = b.next) != null &&
|
||||
s != b && s.isMatched() &&
|
||||
(n = s.next) != null && n != s)
|
||||
b.casNext(s, n);
|
||||
}
|
||||
|
||||
this.lastRet = prev;
|
||||
|
||||
for (Node p = prev, s, n;;) {
|
||||
s = (p == null) ? head : p.next;
|
||||
if (s == null)
|
||||
break;
|
||||
else if (s == p) {
|
||||
p = null;
|
||||
continue;
|
||||
}
|
||||
Object item = s.item;
|
||||
if (s.isData) {
|
||||
if (item != null && item != s) {
|
||||
nextItem = LinkedTransferQueue.<E>cast(item);
|
||||
nextNode = s;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
// assert s.isMatched();
|
||||
if (p == null)
|
||||
p = s;
|
||||
else if ((n = s.next) == null)
|
||||
break;
|
||||
else if (s == n)
|
||||
p = null;
|
||||
else
|
||||
p.casNext(s, n);
|
||||
}
|
||||
nextNode = null;
|
||||
nextItem = null;
|
||||
}
|
||||
|
||||
Itr() {
|
||||
@ -844,10 +884,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
public final void remove() {
|
||||
Node p = lastRet;
|
||||
if (p == null) throw new IllegalStateException();
|
||||
if (p.tryMatchData())
|
||||
unsplice(lastPred, p);
|
||||
final Node lastRet = this.lastRet;
|
||||
if (lastRet == null)
|
||||
throw new IllegalStateException();
|
||||
this.lastRet = null;
|
||||
if (lastRet.tryMatchData())
|
||||
unsplice(lastPred, lastRet);
|
||||
}
|
||||
}
|
||||
|
||||
@ -997,8 +1039,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
* Inserts the specified element at the tail of this queue.
|
||||
* As the queue is unbounded, this method will never return {@code false}.
|
||||
*
|
||||
* @return {@code true} (as specified by
|
||||
* {@link BlockingQueue#offer(Object) BlockingQueue.offer})
|
||||
* @return {@code true} (as specified by {@link Queue#offer})
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offer(E e) {
|
||||
@ -1130,15 +1171,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the elements in this queue in proper
|
||||
* sequence, from head to tail.
|
||||
* Returns an iterator over the elements in this queue in proper sequence.
|
||||
* The elements will be returned in order from first (head) to last (tail).
|
||||
*
|
||||
* <p>The returned iterator is a "weakly consistent" iterator that
|
||||
* will never throw
|
||||
* {@link ConcurrentModificationException ConcurrentModificationException},
|
||||
* and guarantees to traverse elements as they existed upon
|
||||
* construction of the iterator, and may (but is not guaranteed
|
||||
* to) reflect any modifications subsequent to construction.
|
||||
* will never throw {@link java.util.ConcurrentModificationException
|
||||
* ConcurrentModificationException}, and guarantees to traverse
|
||||
* elements as they existed upon construction of the iterator, and
|
||||
* may (but is not guaranteed to) reflect any modifications
|
||||
* subsequent to construction.
|
||||
*
|
||||
* @return an iterator over the elements in this queue in proper sequence
|
||||
*/
|
||||
@ -1202,6 +1243,28 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
||||
return findAndRemove(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this queue contains the specified element.
|
||||
* More formally, returns {@code true} if and only if this queue contains
|
||||
* at least one element {@code e} such that {@code o.equals(e)}.
|
||||
*
|
||||
* @param o object to be checked for containment in this queue
|
||||
* @return {@code true} if this queue contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
if (o == null) return false;
|
||||
for (Node p = head; p != null; p = succ(p)) {
|
||||
Object item = p.item;
|
||||
if (p.isData) {
|
||||
if (item != null && item != p && o.equals(item))
|
||||
return true;
|
||||
}
|
||||
else if (item == null)
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code Integer.MAX_VALUE} because a
|
||||
* {@code LinkedTransferQueue} is not capacity constrained.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,11 +43,11 @@ import java.util.*;
|
||||
* the same ordering rules as class {@link PriorityQueue} and supplies
|
||||
* blocking retrieval operations. While this queue is logically
|
||||
* unbounded, attempted additions may fail due to resource exhaustion
|
||||
* (causing <tt>OutOfMemoryError</tt>). This class does not permit
|
||||
* <tt>null</tt> elements. A priority queue relying on {@linkplain
|
||||
* (causing {@code OutOfMemoryError}). This class does not permit
|
||||
* {@code null} elements. A priority queue relying on {@linkplain
|
||||
* Comparable natural ordering} also does not permit insertion of
|
||||
* non-comparable objects (doing so results in
|
||||
* <tt>ClassCastException</tt>).
|
||||
* {@code ClassCastException}).
|
||||
*
|
||||
* <p>This class and its iterator implement all of the
|
||||
* <em>optional</em> methods of the {@link Collection} and {@link
|
||||
@ -55,7 +55,7 @@ import java.util.*;
|
||||
* #iterator()} is <em>not</em> guaranteed to traverse the elements of
|
||||
* the PriorityBlockingQueue in any particular order. If you need
|
||||
* ordered traversal, consider using
|
||||
* <tt>Arrays.sort(pq.toArray())</tt>. Also, method <tt>drainTo</tt>
|
||||
* {@code Arrays.sort(pq.toArray())}. Also, method {@code drainTo}
|
||||
* can be used to <em>remove</em> some or all elements in priority
|
||||
* order and place them in another collection.
|
||||
*
|
||||
@ -65,12 +65,12 @@ import java.util.*;
|
||||
* secondary key to break ties in primary priority values. For
|
||||
* example, here is a class that applies first-in-first-out
|
||||
* tie-breaking to comparable elements. To use it, you would insert a
|
||||
* <tt>new FIFOEntry(anEntry)</tt> instead of a plain entry object.
|
||||
* {@code new FIFOEntry(anEntry)} instead of a plain entry object.
|
||||
*
|
||||
* <pre>
|
||||
* class FIFOEntry<E extends Comparable<? super E>>
|
||||
* implements Comparable<FIFOEntry<E>> {
|
||||
* final static AtomicLong seq = new AtomicLong();
|
||||
* <pre> {@code
|
||||
* class FIFOEntry<E extends Comparable<? super E>>
|
||||
* implements Comparable<FIFOEntry<E>> {
|
||||
* static final AtomicLong seq = new AtomicLong(0);
|
||||
* final long seqNum;
|
||||
* final E entry;
|
||||
* public FIFOEntry(E entry) {
|
||||
@ -78,13 +78,13 @@ import java.util.*;
|
||||
* this.entry = entry;
|
||||
* }
|
||||
* public E getEntry() { return entry; }
|
||||
* public int compareTo(FIFOEntry<E> other) {
|
||||
* public int compareTo(FIFOEntry<E> other) {
|
||||
* int res = entry.compareTo(other.entry);
|
||||
* if (res == 0 && other.entry != this.entry)
|
||||
* res = (seqNum < other.seqNum ? -1 : 1);
|
||||
* if (res == 0 && other.entry != this.entry)
|
||||
* res = (seqNum < other.seqNum ? -1 : 1);
|
||||
* return res;
|
||||
* }
|
||||
* }</pre>
|
||||
* }}</pre>
|
||||
*
|
||||
* <p>This class is a member of the
|
||||
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
|
||||
@ -98,34 +98,102 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
implements BlockingQueue<E>, java.io.Serializable {
|
||||
private static final long serialVersionUID = 5595510919245408276L;
|
||||
|
||||
private final PriorityQueue<E> q;
|
||||
private final ReentrantLock lock = new ReentrantLock(true);
|
||||
private final Condition notEmpty = lock.newCondition();
|
||||
/*
|
||||
* The implementation uses an array-based binary heap, with public
|
||||
* operations protected with a single lock. However, allocation
|
||||
* during resizing uses a simple spinlock (used only while not
|
||||
* holding main lock) in order to allow takes to operate
|
||||
* concurrently with allocation. This avoids repeated
|
||||
* postponement of waiting consumers and consequent element
|
||||
* build-up. The need to back away from lock during allocation
|
||||
* makes it impossible to simply wrap delegated
|
||||
* java.util.PriorityQueue operations within a lock, as was done
|
||||
* in a previous version of this class. To maintain
|
||||
* interoperability, a plain PriorityQueue is still used during
|
||||
* serialization, which maintains compatibility at the espense of
|
||||
* transiently doubling overhead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a <tt>PriorityBlockingQueue</tt> with the default
|
||||
* Default array capacity.
|
||||
*/
|
||||
private static final int DEFAULT_INITIAL_CAPACITY = 11;
|
||||
|
||||
/**
|
||||
* The maximum size of array to allocate.
|
||||
* Some VMs reserve some header words in an array.
|
||||
* Attempts to allocate larger arrays may result in
|
||||
* OutOfMemoryError: Requested array size exceeds VM limit
|
||||
*/
|
||||
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
||||
|
||||
/**
|
||||
* Priority queue represented as a balanced binary heap: the two
|
||||
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
|
||||
* priority queue is ordered by comparator, or by the elements'
|
||||
* natural ordering, if comparator is null: For each node n in the
|
||||
* heap and each descendant d of n, n <= d. The element with the
|
||||
* lowest value is in queue[0], assuming the queue is nonempty.
|
||||
*/
|
||||
private transient Object[] queue;
|
||||
|
||||
/**
|
||||
* The number of elements in the priority queue.
|
||||
*/
|
||||
private transient int size;
|
||||
|
||||
/**
|
||||
* The comparator, or null if priority queue uses elements'
|
||||
* natural ordering.
|
||||
*/
|
||||
private transient Comparator<? super E> comparator;
|
||||
|
||||
/**
|
||||
* Lock used for all public operations
|
||||
*/
|
||||
private final ReentrantLock lock;
|
||||
|
||||
/**
|
||||
* Condition for blocking when empty
|
||||
*/
|
||||
private final Condition notEmpty;
|
||||
|
||||
/**
|
||||
* Spinlock for allocation, acquired via CAS.
|
||||
*/
|
||||
private transient volatile int allocationSpinLock;
|
||||
|
||||
/**
|
||||
* A plain PriorityQueue used only for serialization,
|
||||
* to maintain compatibility with previous versions
|
||||
* of this class. Non-null only during serialization/deserialization.
|
||||
*/
|
||||
private PriorityQueue q;
|
||||
|
||||
/**
|
||||
* Creates a {@code PriorityBlockingQueue} with the default
|
||||
* initial capacity (11) that orders its elements according to
|
||||
* their {@linkplain Comparable natural ordering}.
|
||||
*/
|
||||
public PriorityBlockingQueue() {
|
||||
q = new PriorityQueue<E>();
|
||||
this(DEFAULT_INITIAL_CAPACITY, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <tt>PriorityBlockingQueue</tt> with the specified
|
||||
* Creates a {@code PriorityBlockingQueue} with the specified
|
||||
* initial capacity that orders its elements according to their
|
||||
* {@linkplain Comparable natural ordering}.
|
||||
*
|
||||
* @param initialCapacity the initial capacity for this priority queue
|
||||
* @throws IllegalArgumentException if <tt>initialCapacity</tt> is less
|
||||
* @throws IllegalArgumentException if {@code initialCapacity} is less
|
||||
* than 1
|
||||
*/
|
||||
public PriorityBlockingQueue(int initialCapacity) {
|
||||
q = new PriorityQueue<E>(initialCapacity, null);
|
||||
this(initialCapacity, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <tt>PriorityBlockingQueue</tt> with the specified initial
|
||||
* Creates a {@code PriorityBlockingQueue} with the specified initial
|
||||
* capacity that orders its elements according to the specified
|
||||
* comparator.
|
||||
*
|
||||
@ -133,16 +201,21 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* @param comparator the comparator that will be used to order this
|
||||
* priority queue. If {@code null}, the {@linkplain Comparable
|
||||
* natural ordering} of the elements will be used.
|
||||
* @throws IllegalArgumentException if <tt>initialCapacity</tt> is less
|
||||
* @throws IllegalArgumentException if {@code initialCapacity} is less
|
||||
* than 1
|
||||
*/
|
||||
public PriorityBlockingQueue(int initialCapacity,
|
||||
Comparator<? super E> comparator) {
|
||||
q = new PriorityQueue<E>(initialCapacity, comparator);
|
||||
if (initialCapacity < 1)
|
||||
throw new IllegalArgumentException();
|
||||
this.lock = new ReentrantLock();
|
||||
this.notEmpty = lock.newCondition();
|
||||
this.comparator = comparator;
|
||||
this.queue = new Object[initialCapacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <tt>PriorityBlockingQueue</tt> containing the elements
|
||||
* Creates a {@code PriorityBlockingQueue} containing the elements
|
||||
* in the specified collection. If the specified collection is a
|
||||
* {@link SortedSet} or a {@link PriorityQueue}, this
|
||||
* priority queue will be ordered according to the same ordering.
|
||||
@ -158,14 +231,215 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* of its elements are null
|
||||
*/
|
||||
public PriorityBlockingQueue(Collection<? extends E> c) {
|
||||
q = new PriorityQueue<E>(c);
|
||||
this.lock = new ReentrantLock();
|
||||
this.notEmpty = lock.newCondition();
|
||||
boolean heapify = true; // true if not known to be in heap order
|
||||
boolean screen = true; // true if must screen for nulls
|
||||
if (c instanceof SortedSet<?>) {
|
||||
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
|
||||
this.comparator = (Comparator<? super E>) ss.comparator();
|
||||
heapify = false;
|
||||
}
|
||||
else if (c instanceof PriorityBlockingQueue<?>) {
|
||||
PriorityBlockingQueue<? extends E> pq =
|
||||
(PriorityBlockingQueue<? extends E>) c;
|
||||
this.comparator = (Comparator<? super E>) pq.comparator();
|
||||
screen = false;
|
||||
if (pq.getClass() == PriorityBlockingQueue.class) // exact match
|
||||
heapify = false;
|
||||
}
|
||||
Object[] a = c.toArray();
|
||||
int n = a.length;
|
||||
// If c.toArray incorrectly doesn't return Object[], copy it.
|
||||
if (a.getClass() != Object[].class)
|
||||
a = Arrays.copyOf(a, n, Object[].class);
|
||||
if (screen && (n == 1 || this.comparator != null)) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (a[i] == null)
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.queue = a;
|
||||
this.size = n;
|
||||
if (heapify)
|
||||
heapify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to grow array to accommodate at least one more element
|
||||
* (but normally expand by about 50%), giving up (allowing retry)
|
||||
* on contention (which we expect to be rare). Call only while
|
||||
* holding lock.
|
||||
*
|
||||
* @param array the heap array
|
||||
* @param oldCap the length of the array
|
||||
*/
|
||||
private void tryGrow(Object[] array, int oldCap) {
|
||||
lock.unlock(); // must release and then re-acquire main lock
|
||||
Object[] newArray = null;
|
||||
if (allocationSpinLock == 0 &&
|
||||
UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
|
||||
0, 1)) {
|
||||
try {
|
||||
int newCap = oldCap + ((oldCap < 64) ?
|
||||
(oldCap + 2) : // grow faster if small
|
||||
(oldCap >> 1));
|
||||
if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow
|
||||
int minCap = oldCap + 1;
|
||||
if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
|
||||
throw new OutOfMemoryError();
|
||||
newCap = MAX_ARRAY_SIZE;
|
||||
}
|
||||
if (newCap > oldCap && queue == array)
|
||||
newArray = new Object[newCap];
|
||||
} finally {
|
||||
allocationSpinLock = 0;
|
||||
}
|
||||
}
|
||||
if (newArray == null) // back off if another thread is allocating
|
||||
Thread.yield();
|
||||
lock.lock();
|
||||
if (newArray != null && queue == array) {
|
||||
queue = newArray;
|
||||
System.arraycopy(array, 0, newArray, 0, oldCap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mechanics for poll(). Call only while holding lock.
|
||||
*/
|
||||
private E extract() {
|
||||
E result;
|
||||
int n = size - 1;
|
||||
if (n < 0)
|
||||
result = null;
|
||||
else {
|
||||
Object[] array = queue;
|
||||
result = (E) array[0];
|
||||
E x = (E) array[n];
|
||||
array[n] = null;
|
||||
Comparator<? super E> cmp = comparator;
|
||||
if (cmp == null)
|
||||
siftDownComparable(0, x, array, n);
|
||||
else
|
||||
siftDownUsingComparator(0, x, array, n, cmp);
|
||||
size = n;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts item x at position k, maintaining heap invariant by
|
||||
* promoting x up the tree until it is greater than or equal to
|
||||
* its parent, or is the root.
|
||||
*
|
||||
* To simplify and speed up coercions and comparisons. the
|
||||
* Comparable and Comparator versions are separated into different
|
||||
* methods that are otherwise identical. (Similarly for siftDown.)
|
||||
* These methods are static, with heap state as arguments, to
|
||||
* simplify use in light of possible comparator exceptions.
|
||||
*
|
||||
* @param k the position to fill
|
||||
* @param x the item to insert
|
||||
* @param array the heap array
|
||||
* @param n heap size
|
||||
*/
|
||||
private static <T> void siftUpComparable(int k, T x, Object[] array) {
|
||||
Comparable<? super T> key = (Comparable<? super T>) x;
|
||||
while (k > 0) {
|
||||
int parent = (k - 1) >>> 1;
|
||||
Object e = array[parent];
|
||||
if (key.compareTo((T) e) >= 0)
|
||||
break;
|
||||
array[k] = e;
|
||||
k = parent;
|
||||
}
|
||||
array[k] = key;
|
||||
}
|
||||
|
||||
private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
|
||||
Comparator<? super T> cmp) {
|
||||
while (k > 0) {
|
||||
int parent = (k - 1) >>> 1;
|
||||
Object e = array[parent];
|
||||
if (cmp.compare(x, (T) e) >= 0)
|
||||
break;
|
||||
array[k] = e;
|
||||
k = parent;
|
||||
}
|
||||
array[k] = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts item x at position k, maintaining heap invariant by
|
||||
* demoting x down the tree repeatedly until it is less than or
|
||||
* equal to its children or is a leaf.
|
||||
*
|
||||
* @param k the position to fill
|
||||
* @param x the item to insert
|
||||
* @param array the heap array
|
||||
* @param n heap size
|
||||
*/
|
||||
private static <T> void siftDownComparable(int k, T x, Object[] array,
|
||||
int n) {
|
||||
Comparable<? super T> key = (Comparable<? super T>)x;
|
||||
int half = n >>> 1; // loop while a non-leaf
|
||||
while (k < half) {
|
||||
int child = (k << 1) + 1; // assume left child is least
|
||||
Object c = array[child];
|
||||
int right = child + 1;
|
||||
if (right < n &&
|
||||
((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
|
||||
c = array[child = right];
|
||||
if (key.compareTo((T) c) <= 0)
|
||||
break;
|
||||
array[k] = c;
|
||||
k = child;
|
||||
}
|
||||
array[k] = key;
|
||||
}
|
||||
|
||||
private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
|
||||
int n,
|
||||
Comparator<? super T> cmp) {
|
||||
int half = n >>> 1;
|
||||
while (k < half) {
|
||||
int child = (k << 1) + 1;
|
||||
Object c = array[child];
|
||||
int right = child + 1;
|
||||
if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
|
||||
c = array[child = right];
|
||||
if (cmp.compare(x, (T) c) <= 0)
|
||||
break;
|
||||
array[k] = c;
|
||||
k = child;
|
||||
}
|
||||
array[k] = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the heap invariant (described above) in the entire tree,
|
||||
* assuming nothing about the order of the elements prior to the call.
|
||||
*/
|
||||
private void heapify() {
|
||||
Object[] array = queue;
|
||||
int n = size;
|
||||
int half = (n >>> 1) - 1;
|
||||
Comparator<? super E> cmp = comparator;
|
||||
if (cmp == null) {
|
||||
for (int i = half; i >= 0; i--)
|
||||
siftDownComparable(i, (E) array[i], array, n);
|
||||
}
|
||||
else {
|
||||
for (int i = half; i >= 0; i--)
|
||||
siftDownUsingComparator(i, (E) array[i], array, n, cmp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element into this priority queue.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @return <tt>true</tt> (as specified by {@link Collection#add})
|
||||
* @return {@code true} (as specified by {@link Collection#add})
|
||||
* @throws ClassCastException if the specified element cannot be compared
|
||||
* with elements currently in the priority queue according to the
|
||||
* priority queue's ordering
|
||||
@ -177,30 +451,41 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
|
||||
/**
|
||||
* Inserts the specified element into this priority queue.
|
||||
* As the queue is unbounded, this method will never return {@code false}.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @return <tt>true</tt> (as specified by {@link Queue#offer})
|
||||
* @return {@code true} (as specified by {@link Queue#offer})
|
||||
* @throws ClassCastException if the specified element cannot be compared
|
||||
* with elements currently in the priority queue according to the
|
||||
* priority queue's ordering
|
||||
* @throws NullPointerException if the specified element is null
|
||||
*/
|
||||
public boolean offer(E e) {
|
||||
if (e == null)
|
||||
throw new NullPointerException();
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
int n, cap;
|
||||
Object[] array;
|
||||
while ((n = size) >= (cap = (array = queue).length))
|
||||
tryGrow(array, cap);
|
||||
try {
|
||||
boolean ok = q.offer(e);
|
||||
assert ok;
|
||||
Comparator<? super E> cmp = comparator;
|
||||
if (cmp == null)
|
||||
siftUpComparable(n, e, array);
|
||||
else
|
||||
siftUpUsingComparator(n, e, array, cmp);
|
||||
size = n + 1;
|
||||
notEmpty.signal();
|
||||
return true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element into this priority queue. As the queue is
|
||||
* unbounded this method will never block.
|
||||
* Inserts the specified element into this priority queue.
|
||||
* As the queue is unbounded, this method will never block.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @throws ClassCastException if the specified element cannot be compared
|
||||
@ -213,13 +498,15 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified element into this priority queue. As the queue is
|
||||
* unbounded this method will never block.
|
||||
* Inserts the specified element into this priority queue.
|
||||
* As the queue is unbounded, this method will never block or
|
||||
* return {@code false}.
|
||||
*
|
||||
* @param e the element to add
|
||||
* @param timeout This parameter is ignored as the method never blocks
|
||||
* @param unit This parameter is ignored as the method never blocks
|
||||
* @return <tt>true</tt>
|
||||
* @return {@code true} (as specified by
|
||||
* {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
|
||||
* @throws ClassCastException if the specified element cannot be compared
|
||||
* with elements currently in the priority queue according to the
|
||||
* priority queue's ordering
|
||||
@ -232,97 +519,123 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
public E poll() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
E result;
|
||||
try {
|
||||
return q.poll();
|
||||
result = extract();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public E take() throws InterruptedException {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lockInterruptibly();
|
||||
E result;
|
||||
try {
|
||||
try {
|
||||
while (q.size() == 0)
|
||||
notEmpty.await();
|
||||
} catch (InterruptedException ie) {
|
||||
notEmpty.signal(); // propagate to non-interrupted thread
|
||||
throw ie;
|
||||
}
|
||||
E x = q.poll();
|
||||
assert x != null;
|
||||
return x;
|
||||
while ( (result = extract()) == null)
|
||||
notEmpty.await();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
long nanos = unit.toNanos(timeout);
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lockInterruptibly();
|
||||
E result;
|
||||
try {
|
||||
for (;;) {
|
||||
E x = q.poll();
|
||||
if (x != null)
|
||||
return x;
|
||||
if (nanos <= 0)
|
||||
return null;
|
||||
try {
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
} catch (InterruptedException ie) {
|
||||
notEmpty.signal(); // propagate to non-interrupted thread
|
||||
throw ie;
|
||||
}
|
||||
}
|
||||
while ( (result = extract()) == null && nanos > 0)
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public E peek() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
E result;
|
||||
try {
|
||||
return q.peek();
|
||||
result = size > 0 ? (E) queue[0] : null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the comparator used to order the elements in this queue,
|
||||
* or <tt>null</tt> if this queue uses the {@linkplain Comparable
|
||||
* or {@code null} if this queue uses the {@linkplain Comparable
|
||||
* natural ordering} of its elements.
|
||||
*
|
||||
* @return the comparator used to order the elements in this queue,
|
||||
* or <tt>null</tt> if this queue uses the natural
|
||||
* or {@code null} if this queue uses the natural
|
||||
* ordering of its elements
|
||||
*/
|
||||
public Comparator<? super E> comparator() {
|
||||
return q.comparator();
|
||||
return comparator;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return q.size();
|
||||
return size;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns <tt>Integer.MAX_VALUE</tt> because
|
||||
* a <tt>PriorityBlockingQueue</tt> is not capacity constrained.
|
||||
* @return <tt>Integer.MAX_VALUE</tt>
|
||||
* Always returns {@code Integer.MAX_VALUE} because
|
||||
* a {@code PriorityBlockingQueue} is not capacity constrained.
|
||||
* @return {@code Integer.MAX_VALUE} always
|
||||
*/
|
||||
public int remainingCapacity() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
private int indexOf(Object o) {
|
||||
if (o != null) {
|
||||
Object[] array = queue;
|
||||
int n = size;
|
||||
for (int i = 0; i < n; i++)
|
||||
if (o.equals(array[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the ith element from queue.
|
||||
*/
|
||||
private void removeAt(int i) {
|
||||
Object[] array = queue;
|
||||
int n = size - 1;
|
||||
if (n == i) // removed last element
|
||||
array[i] = null;
|
||||
else {
|
||||
E moved = (E) array[n];
|
||||
array[n] = null;
|
||||
Comparator<? super E> cmp = comparator;
|
||||
if (cmp == null)
|
||||
siftDownComparable(i, moved, array, n);
|
||||
else
|
||||
siftDownUsingComparator(i, moved, array, n, cmp);
|
||||
if (array[i] == moved) {
|
||||
if (cmp == null)
|
||||
siftUpComparable(i, moved, array);
|
||||
else
|
||||
siftUpUsingComparator(i, moved, array, cmp);
|
||||
}
|
||||
}
|
||||
size = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a single instance of the specified element from this queue,
|
||||
* if it is present. More formally, removes an element {@code e} such
|
||||
@ -332,13 +645,40 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* result of the call).
|
||||
*
|
||||
* @param o element to be removed from this queue, if present
|
||||
* @return <tt>true</tt> if this queue changed as a result of the call
|
||||
* @return {@code true} if this queue changed as a result of the call
|
||||
*/
|
||||
public boolean remove(Object o) {
|
||||
boolean removed = false;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return q.remove(o);
|
||||
int i = indexOf(o);
|
||||
if (i != -1) {
|
||||
removeAt(i);
|
||||
removed = true;
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Identity-based version for use in Itr.remove
|
||||
*/
|
||||
private void removeEQ(Object o) {
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
Object[] array = queue;
|
||||
int n = size;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (o == array[i]) {
|
||||
removeAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -350,16 +690,18 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* at least one element {@code e} such that {@code o.equals(e)}.
|
||||
*
|
||||
* @param o object to be checked for containment in this queue
|
||||
* @return <tt>true</tt> if this queue contains the specified element
|
||||
* @return {@code true} if this queue contains the specified element
|
||||
*/
|
||||
public boolean contains(Object o) {
|
||||
int index;
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return q.contains(o);
|
||||
index = indexOf(o);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return index != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -379,7 +721,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return q.toArray();
|
||||
return Arrays.copyOf(queue, size);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -390,7 +732,18 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return q.toString();
|
||||
int n = size;
|
||||
if (n == 0)
|
||||
return "[]";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[');
|
||||
for (int i = 0; i < n; ++i) {
|
||||
E e = (E)queue[i];
|
||||
sb.append(e == this ? "(this Collection)" : e);
|
||||
if (i != n - 1)
|
||||
sb.append(',').append(' ');
|
||||
}
|
||||
return sb.append(']').toString();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -412,7 +765,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
try {
|
||||
int n = 0;
|
||||
E e;
|
||||
while ( (e = q.poll()) != null) {
|
||||
while ( (e = extract()) != null) {
|
||||
c.add(e);
|
||||
++n;
|
||||
}
|
||||
@ -440,7 +793,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
try {
|
||||
int n = 0;
|
||||
E e;
|
||||
while (n < maxElements && (e = q.poll()) != null) {
|
||||
while (n < maxElements && (e = extract()) != null) {
|
||||
c.add(e);
|
||||
++n;
|
||||
}
|
||||
@ -458,7 +811,11 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
q.clear();
|
||||
Object[] array = queue;
|
||||
int n = size;
|
||||
size = 0;
|
||||
for (int i = 0; i < n; i++)
|
||||
array[i] = null;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -475,22 +832,22 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
* <p>If this queue fits in the specified array with room to spare
|
||||
* (i.e., the array has more elements than this queue), the element in
|
||||
* the array immediately following the end of the queue is set to
|
||||
* <tt>null</tt>.
|
||||
* {@code null}.
|
||||
*
|
||||
* <p>Like the {@link #toArray()} method, this method acts as bridge between
|
||||
* array-based and collection-based APIs. Further, this method allows
|
||||
* precise control over the runtime type of the output array, and may,
|
||||
* under certain circumstances, be used to save allocation costs.
|
||||
*
|
||||
* <p>Suppose <tt>x</tt> is a queue known to contain only strings.
|
||||
* <p>Suppose {@code x} is a queue known to contain only strings.
|
||||
* The following code can be used to dump the queue into a newly
|
||||
* allocated array of <tt>String</tt>:
|
||||
* allocated array of {@code String}:
|
||||
*
|
||||
* <pre>
|
||||
* String[] y = x.toArray(new String[0]);</pre>
|
||||
*
|
||||
* Note that <tt>toArray(new Object[0])</tt> is identical in function to
|
||||
* <tt>toArray()</tt>.
|
||||
* Note that {@code toArray(new Object[0])} is identical in function to
|
||||
* {@code toArray()}.
|
||||
*
|
||||
* @param a the array into which the elements of the queue are to
|
||||
* be stored, if it is big enough; otherwise, a new array of the
|
||||
@ -505,7 +862,14 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
final ReentrantLock lock = this.lock;
|
||||
lock.lock();
|
||||
try {
|
||||
return q.toArray(a);
|
||||
int n = size;
|
||||
if (a.length < n)
|
||||
// Make a new array of a's runtime type, but my contents:
|
||||
return (T[]) Arrays.copyOf(queue, size, a.getClass());
|
||||
System.arraycopy(queue, 0, a, 0, n);
|
||||
if (a.length > n)
|
||||
a[n] = null;
|
||||
return a;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
@ -514,8 +878,9 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
/**
|
||||
* Returns an iterator over the elements in this queue. The
|
||||
* iterator does not return the elements in any particular order.
|
||||
* The returned <tt>Iterator</tt> is a "weakly consistent"
|
||||
* iterator that will never throw {@link
|
||||
*
|
||||
* <p>The returned iterator is a "weakly consistent" iterator that
|
||||
* will never throw {@link java.util.ConcurrentModificationException
|
||||
* ConcurrentModificationException}, and guarantees to traverse
|
||||
* elements as they existed upon construction of the iterator, and
|
||||
* may (but is not guaranteed to) reflect any modifications
|
||||
@ -530,7 +895,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
/**
|
||||
* Snapshot iterator that works off copy of underlying q array.
|
||||
*/
|
||||
private class Itr implements Iterator<E> {
|
||||
final class Itr implements Iterator<E> {
|
||||
final Object[] array; // Array of all elements
|
||||
int cursor; // index of next element to return;
|
||||
int lastRet; // index of last element, or -1 if no such
|
||||
@ -554,39 +919,65 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
||||
public void remove() {
|
||||
if (lastRet < 0)
|
||||
throw new IllegalStateException();
|
||||
Object x = array[lastRet];
|
||||
removeEQ(array[lastRet]);
|
||||
lastRet = -1;
|
||||
// Traverse underlying queue to find == element,
|
||||
// not just a .equals element.
|
||||
lock.lock();
|
||||
try {
|
||||
for (Iterator it = q.iterator(); it.hasNext(); ) {
|
||||
if (it.next() == x) {
|
||||
it.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the state to a stream (that is, serializes it). This
|
||||
* merely wraps default serialization within lock. The
|
||||
* serialization strategy for items is left to underlying
|
||||
* Queue. Note that locking is not needed on deserialization, so
|
||||
* readObject is not defined, just relying on default.
|
||||
* Saves the state to a stream (that is, serializes it). For
|
||||
* compatibility with previous version of this class,
|
||||
* elements are first copied to a java.util.PriorityQueue,
|
||||
* which is then serialized.
|
||||
*/
|
||||
private void writeObject(java.io.ObjectOutputStream s)
|
||||
throws java.io.IOException {
|
||||
lock.lock();
|
||||
try {
|
||||
int n = size; // avoid zero capacity argument
|
||||
q = new PriorityQueue<E>(n == 0 ? 1 : n, comparator);
|
||||
q.addAll(this);
|
||||
s.defaultWriteObject();
|
||||
} finally {
|
||||
q = null;
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstitutes the {@code PriorityBlockingQueue} instance from a stream
|
||||
* (that is, deserializes it).
|
||||
*
|
||||
* @param s the stream
|
||||
*/
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws java.io.IOException, ClassNotFoundException {
|
||||
try {
|
||||
s.defaultReadObject();
|
||||
this.queue = new Object[q.size()];
|
||||
comparator = q.comparator();
|
||||
addAll(q);
|
||||
} finally {
|
||||
q = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long allocationSpinLockOffset =
|
||||
objectFieldOffset(UNSAFE, "allocationSpinLock",
|
||||
PriorityBlockingQueue.class);
|
||||
|
||||
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
|
||||
String field, Class<?> klazz) {
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Convert Exception to corresponding Error
|
||||
NoSuchFieldError error = new NoSuchFieldError(field);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -360,8 +360,12 @@ public class ScheduledThreadPoolExecutor
|
||||
getExecuteExistingDelayedTasksAfterShutdownPolicy();
|
||||
boolean keepPeriodic =
|
||||
getContinueExistingPeriodicTasksAfterShutdownPolicy();
|
||||
if (!keepDelayed && !keepPeriodic)
|
||||
if (!keepDelayed && !keepPeriodic) {
|
||||
for (Object e : q.toArray())
|
||||
if (e instanceof RunnableScheduledFuture<?>)
|
||||
((RunnableScheduledFuture<?>) e).cancel(false);
|
||||
q.clear();
|
||||
}
|
||||
else {
|
||||
// Traverse snapshot to avoid iterator exceptions
|
||||
for (Object e : q.toArray()) {
|
||||
|
@ -163,7 +163,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
/**
|
||||
* Shared internal API for dual stacks and queues.
|
||||
*/
|
||||
static abstract class Transferer {
|
||||
abstract static class Transferer {
|
||||
/**
|
||||
* Performs a put or take.
|
||||
*
|
||||
@ -190,7 +190,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* seems not to vary with number of CPUs (beyond 2) so is just
|
||||
* a constant.
|
||||
*/
|
||||
static final int maxTimedSpins = (NCPUS < 2)? 0 : 32;
|
||||
static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
|
||||
|
||||
/**
|
||||
* The number of times to spin before blocking in untimed waits.
|
||||
@ -241,19 +241,11 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<SNode, SNode>
|
||||
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(SNode.class, SNode.class, "next");
|
||||
|
||||
boolean casNext(SNode cmp, SNode val) {
|
||||
return (cmp == next &&
|
||||
nextUpdater.compareAndSet(this, cmp, val));
|
||||
return cmp == next &&
|
||||
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<SNode, SNode>
|
||||
matchUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(SNode.class, SNode.class, "match");
|
||||
|
||||
/**
|
||||
* Tries to match node s to this node, if so, waking up thread.
|
||||
* Fulfillers call tryMatch to identify their waiters.
|
||||
@ -264,7 +256,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
boolean tryMatch(SNode s) {
|
||||
if (match == null &&
|
||||
matchUpdater.compareAndSet(this, null, s)) {
|
||||
UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
|
||||
Thread w = waiter;
|
||||
if (w != null) { // waiters need at most one unpark
|
||||
waiter = null;
|
||||
@ -279,23 +271,28 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* Tries to cancel a wait by matching node to itself.
|
||||
*/
|
||||
void tryCancel() {
|
||||
matchUpdater.compareAndSet(this, null, this);
|
||||
UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
return match == this;
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long nextOffset =
|
||||
objectFieldOffset(UNSAFE, "next", SNode.class);
|
||||
private static final long matchOffset =
|
||||
objectFieldOffset(UNSAFE, "match", SNode.class);
|
||||
|
||||
}
|
||||
|
||||
/** The head (top) of the stack */
|
||||
volatile SNode head;
|
||||
|
||||
static final AtomicReferenceFieldUpdater<TransferStack, SNode>
|
||||
headUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(TransferStack.class, SNode.class, "head");
|
||||
|
||||
boolean casHead(SNode h, SNode nh) {
|
||||
return h == head && headUpdater.compareAndSet(this, h, nh);
|
||||
return h == head &&
|
||||
UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,7 +335,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
|
||||
SNode s = null; // constructed/reused as needed
|
||||
int mode = (e == null)? REQUEST : DATA;
|
||||
int mode = (e == null) ? REQUEST : DATA;
|
||||
|
||||
for (;;) {
|
||||
SNode h = head;
|
||||
@ -356,7 +353,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
if ((h = head) != null && h.next == s)
|
||||
casHead(h, s.next); // help s's fulfiller
|
||||
return mode == REQUEST? m.item : s.item;
|
||||
return (mode == REQUEST) ? m.item : s.item;
|
||||
}
|
||||
} else if (!isFulfilling(h.mode)) { // try to fulfill
|
||||
if (h.isCancelled()) // already cancelled
|
||||
@ -372,7 +369,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
SNode mn = m.next;
|
||||
if (m.tryMatch(s)) {
|
||||
casHead(s, mn); // pop both s and m
|
||||
return (mode == REQUEST)? m.item : s.item;
|
||||
return (mode == REQUEST) ? m.item : s.item;
|
||||
} else // lost match
|
||||
s.casNext(m, mn); // help unlink
|
||||
}
|
||||
@ -423,11 +420,11 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* and don't wait at all, so are trapped in transfer
|
||||
* method rather than calling awaitFulfill.
|
||||
*/
|
||||
long lastTime = (timed)? System.nanoTime() : 0;
|
||||
long lastTime = timed ? System.nanoTime() : 0;
|
||||
Thread w = Thread.currentThread();
|
||||
SNode h = head;
|
||||
int spins = (shouldSpin(s)?
|
||||
(timed? maxTimedSpins : maxUntimedSpins) : 0);
|
||||
int spins = (shouldSpin(s) ?
|
||||
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
|
||||
for (;;) {
|
||||
if (w.isInterrupted())
|
||||
s.tryCancel();
|
||||
@ -444,7 +441,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
}
|
||||
}
|
||||
if (spins > 0)
|
||||
spins = shouldSpin(s)? (spins-1) : 0;
|
||||
spins = shouldSpin(s) ? (spins-1) : 0;
|
||||
else if (s.waiter == null)
|
||||
s.waiter = w; // establish waiter so can park next iter
|
||||
else if (!timed)
|
||||
@ -499,6 +496,12 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
p = n;
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long headOffset =
|
||||
objectFieldOffset(UNSAFE, "head", TransferStack.class);
|
||||
|
||||
}
|
||||
|
||||
/** Dual Queue */
|
||||
@ -524,29 +527,21 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
this.isData = isData;
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<QNode, QNode>
|
||||
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(QNode.class, QNode.class, "next");
|
||||
|
||||
boolean casNext(QNode cmp, QNode val) {
|
||||
return (next == cmp &&
|
||||
nextUpdater.compareAndSet(this, cmp, val));
|
||||
return next == cmp &&
|
||||
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<QNode, Object>
|
||||
itemUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(QNode.class, Object.class, "item");
|
||||
|
||||
boolean casItem(Object cmp, Object val) {
|
||||
return (item == cmp &&
|
||||
itemUpdater.compareAndSet(this, cmp, val));
|
||||
return item == cmp &&
|
||||
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to cancel by CAS'ing ref to this as item.
|
||||
*/
|
||||
void tryCancel(Object cmp) {
|
||||
itemUpdater.compareAndSet(this, cmp, this);
|
||||
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
@ -561,6 +556,13 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
boolean isOffList() {
|
||||
return next == this;
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long nextOffset =
|
||||
objectFieldOffset(UNSAFE, "next", QNode.class);
|
||||
private static final long itemOffset =
|
||||
objectFieldOffset(UNSAFE, "item", QNode.class);
|
||||
}
|
||||
|
||||
/** Head of queue */
|
||||
@ -580,41 +582,30 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
tail = h;
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<TransferQueue, QNode>
|
||||
headUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(TransferQueue.class, QNode.class, "head");
|
||||
|
||||
/**
|
||||
* Tries to cas nh as new head; if successful, unlink
|
||||
* old head's next node to avoid garbage retention.
|
||||
*/
|
||||
void advanceHead(QNode h, QNode nh) {
|
||||
if (h == head && headUpdater.compareAndSet(this, h, nh))
|
||||
if (h == head &&
|
||||
UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
|
||||
h.next = h; // forget old next
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<TransferQueue, QNode>
|
||||
tailUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(TransferQueue.class, QNode.class, "tail");
|
||||
|
||||
/**
|
||||
* Tries to cas nt as new tail.
|
||||
*/
|
||||
void advanceTail(QNode t, QNode nt) {
|
||||
if (tail == t)
|
||||
tailUpdater.compareAndSet(this, t, nt);
|
||||
UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
|
||||
}
|
||||
|
||||
static final AtomicReferenceFieldUpdater<TransferQueue, QNode>
|
||||
cleanMeUpdater = AtomicReferenceFieldUpdater.newUpdater
|
||||
(TransferQueue.class, QNode.class, "cleanMe");
|
||||
|
||||
/**
|
||||
* Tries to CAS cleanMe slot.
|
||||
*/
|
||||
boolean casCleanMe(QNode cmp, QNode val) {
|
||||
return (cleanMe == cmp &&
|
||||
cleanMeUpdater.compareAndSet(this, cmp, val));
|
||||
return cleanMe == cmp &&
|
||||
UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -683,7 +674,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
s.item = s;
|
||||
s.waiter = null;
|
||||
}
|
||||
return (x != null)? x : e;
|
||||
return (x != null) ? x : e;
|
||||
|
||||
} else { // complementary-mode
|
||||
QNode m = h.next; // node to fulfill
|
||||
@ -700,7 +691,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
|
||||
advanceHead(h, m); // successfully fulfilled
|
||||
LockSupport.unpark(m.waiter);
|
||||
return (x != null)? x : e;
|
||||
return (x != null) ? x : e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -716,10 +707,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
*/
|
||||
Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) {
|
||||
/* Same idea as TransferStack.awaitFulfill */
|
||||
long lastTime = (timed)? System.nanoTime() : 0;
|
||||
long lastTime = timed ? System.nanoTime() : 0;
|
||||
Thread w = Thread.currentThread();
|
||||
int spins = ((head.next == s) ?
|
||||
(timed? maxTimedSpins : maxUntimedSpins) : 0);
|
||||
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
|
||||
for (;;) {
|
||||
if (w.isInterrupted())
|
||||
s.tryCancel(e);
|
||||
@ -799,6 +790,16 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
return; // Postpone cleaning s
|
||||
}
|
||||
}
|
||||
|
||||
// unsafe mechanics
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long headOffset =
|
||||
objectFieldOffset(UNSAFE, "head", TransferQueue.class);
|
||||
private static final long tailOffset =
|
||||
objectFieldOffset(UNSAFE, "tail", TransferQueue.class);
|
||||
private static final long cleanMeOffset =
|
||||
objectFieldOffset(UNSAFE, "cleanMe", TransferQueue.class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -824,7 +825,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
* access; otherwise the order is unspecified.
|
||||
*/
|
||||
public SynchronousQueue(boolean fair) {
|
||||
transferer = (fair)? new TransferQueue() : new TransferStack();
|
||||
transferer = fair ? new TransferQueue() : new TransferStack();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1141,4 +1142,17 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
|
||||
transferer = new TransferStack();
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
|
||||
String field, Class<?> klazz) {
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Convert Exception to corresponding Error
|
||||
NoSuchFieldError error = new NoSuchFieldError(field);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1841,6 +1841,43 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string identifying this pool, as well as its state,
|
||||
* including indications of run state and estimated worker and
|
||||
* task counts.
|
||||
*
|
||||
* @return a string identifying this pool, as well as its state
|
||||
*/
|
||||
public String toString() {
|
||||
long ncompleted;
|
||||
int nworkers, nactive;
|
||||
final ReentrantLock mainLock = this.mainLock;
|
||||
mainLock.lock();
|
||||
try {
|
||||
ncompleted = completedTaskCount;
|
||||
nactive = 0;
|
||||
nworkers = workers.size();
|
||||
for (Worker w : workers) {
|
||||
ncompleted += w.completedTasks;
|
||||
if (w.isLocked())
|
||||
++nactive;
|
||||
}
|
||||
} finally {
|
||||
mainLock.unlock();
|
||||
}
|
||||
int c = ctl.get();
|
||||
String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
|
||||
(runStateAtLeast(c, TERMINATED) ? "Terminated" :
|
||||
"Shutting down"));
|
||||
return super.toString() +
|
||||
"[" + rs +
|
||||
", pool size = " + nworkers +
|
||||
", active threads = " + nactive +
|
||||
", queued tasks = " + workQueue.size() +
|
||||
", completed tasks = " + ncompleted +
|
||||
"]";
|
||||
}
|
||||
|
||||
/* Extension hooks */
|
||||
|
||||
/**
|
||||
@ -1961,7 +1998,9 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
||||
* @throws RejectedExecutionException always.
|
||||
*/
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
|
||||
throw new RejectedExecutionException();
|
||||
throw new RejectedExecutionException("Task " + r.toString() +
|
||||
" rejected from " +
|
||||
e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,28 +48,37 @@ import java.util.*;
|
||||
public class AtomicIntegerArray implements java.io.Serializable {
|
||||
private static final long serialVersionUID = 2862133569453604235L;
|
||||
|
||||
// setup to use Unsafe.compareAndSwapInt for updates
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final int base = unsafe.arrayBaseOffset(int[].class);
|
||||
private static final int scale = unsafe.arrayIndexScale(int[].class);
|
||||
private static final int shift;
|
||||
private final int[] array;
|
||||
|
||||
private long rawIndex(int i) {
|
||||
static {
|
||||
int scale = unsafe.arrayIndexScale(int[].class);
|
||||
if ((scale & (scale - 1)) != 0)
|
||||
throw new Error("data type scale not a power of two");
|
||||
shift = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
}
|
||||
|
||||
private long checkedByteOffset(int i) {
|
||||
if (i < 0 || i >= array.length)
|
||||
throw new IndexOutOfBoundsException("index " + i);
|
||||
return base + (long) i * scale;
|
||||
|
||||
return byteOffset(i);
|
||||
}
|
||||
|
||||
private static long byteOffset(int i) {
|
||||
return ((long) i << shift) + base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AtomicIntegerArray of given length.
|
||||
* Creates a new AtomicIntegerArray of the given length, with all
|
||||
* elements initially zero.
|
||||
*
|
||||
* @param length the length of the array
|
||||
*/
|
||||
public AtomicIntegerArray(int length) {
|
||||
array = new int[length];
|
||||
// must perform at least one volatile write to conform to JMM
|
||||
if (length > 0)
|
||||
unsafe.putIntVolatile(array, rawIndex(0), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -80,17 +89,8 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @throws NullPointerException if array is null
|
||||
*/
|
||||
public AtomicIntegerArray(int[] array) {
|
||||
if (array == null)
|
||||
throw new NullPointerException();
|
||||
int length = array.length;
|
||||
this.array = new int[length];
|
||||
if (length > 0) {
|
||||
int last = length-1;
|
||||
for (int i = 0; i < last; ++i)
|
||||
this.array[i] = array[i];
|
||||
// Do the last write as volatile
|
||||
unsafe.putIntVolatile(this.array, rawIndex(last), array[last]);
|
||||
}
|
||||
// Visibility guaranteed by final field guarantees
|
||||
this.array = array.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,7 +109,11 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the current value
|
||||
*/
|
||||
public final int get(int i) {
|
||||
return unsafe.getIntVolatile(array, rawIndex(i));
|
||||
return getRaw(checkedByteOffset(i));
|
||||
}
|
||||
|
||||
private int getRaw(long offset) {
|
||||
return unsafe.getIntVolatile(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,7 +123,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @param newValue the new value
|
||||
*/
|
||||
public final void set(int i, int newValue) {
|
||||
unsafe.putIntVolatile(array, rawIndex(i), newValue);
|
||||
unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +134,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @since 1.6
|
||||
*/
|
||||
public final void lazySet(int i, int newValue) {
|
||||
unsafe.putOrderedInt(array, rawIndex(i), newValue);
|
||||
unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,9 +146,10 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final int getAndSet(int i, int newValue) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
if (compareAndSet(i, current, newValue))
|
||||
int current = getRaw(offset);
|
||||
if (compareAndSetRaw(offset, current, newValue))
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@ -160,8 +165,11 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* the actual value was not equal to the expected value.
|
||||
*/
|
||||
public final boolean compareAndSet(int i, int expect, int update) {
|
||||
return unsafe.compareAndSwapInt(array, rawIndex(i),
|
||||
expect, update);
|
||||
return compareAndSetRaw(checkedByteOffset(i), expect, update);
|
||||
}
|
||||
|
||||
private boolean compareAndSetRaw(long offset, int expect, int update) {
|
||||
return unsafe.compareAndSwapInt(array, offset, expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,12 +196,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final int getAndIncrement(int i) {
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
int next = current + 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return current;
|
||||
}
|
||||
return getAndAdd(i, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,12 +206,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final int getAndDecrement(int i) {
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
int next = current - 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return current;
|
||||
}
|
||||
return getAndAdd(i, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,10 +217,10 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final int getAndAdd(int i, int delta) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
int next = current + delta;
|
||||
if (compareAndSet(i, current, next))
|
||||
int current = getRaw(offset);
|
||||
if (compareAndSetRaw(offset, current, current + delta))
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@ -234,12 +232,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the updated value
|
||||
*/
|
||||
public final int incrementAndGet(int i) {
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
int next = current + 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return next;
|
||||
}
|
||||
return addAndGet(i, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,12 +242,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the updated value
|
||||
*/
|
||||
public final int decrementAndGet(int i) {
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
int next = current - 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return next;
|
||||
}
|
||||
return addAndGet(i, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,22 +253,32 @@ public class AtomicIntegerArray implements java.io.Serializable {
|
||||
* @return the updated value
|
||||
*/
|
||||
public final int addAndGet(int i, int delta) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
int current = get(i);
|
||||
int current = getRaw(offset);
|
||||
int next = current + delta;
|
||||
if (compareAndSet(i, current, next))
|
||||
if (compareAndSetRaw(offset, current, next))
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String representation of the current values of array.
|
||||
* @return the String representation of the current values of array.
|
||||
* @return the String representation of the current values of array
|
||||
*/
|
||||
public String toString() {
|
||||
if (array.length > 0) // force volatile read
|
||||
get(0);
|
||||
return Arrays.toString(array);
|
||||
int iMax = array.length - 1;
|
||||
if (iMax == -1)
|
||||
return "[]";
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
b.append(getRaw(byteOffset(i)));
|
||||
if (i == iMax)
|
||||
return b.append(']').toString();
|
||||
b.append(',').append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,28 +47,37 @@ import java.util.*;
|
||||
public class AtomicLongArray implements java.io.Serializable {
|
||||
private static final long serialVersionUID = -2308431214976778248L;
|
||||
|
||||
// setup to use Unsafe.compareAndSwapInt for updates
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final int base = unsafe.arrayBaseOffset(long[].class);
|
||||
private static final int scale = unsafe.arrayIndexScale(long[].class);
|
||||
private static final int shift;
|
||||
private final long[] array;
|
||||
|
||||
private long rawIndex(int i) {
|
||||
static {
|
||||
int scale = unsafe.arrayIndexScale(long[].class);
|
||||
if ((scale & (scale - 1)) != 0)
|
||||
throw new Error("data type scale not a power of two");
|
||||
shift = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
}
|
||||
|
||||
private long checkedByteOffset(int i) {
|
||||
if (i < 0 || i >= array.length)
|
||||
throw new IndexOutOfBoundsException("index " + i);
|
||||
return base + (long) i * scale;
|
||||
|
||||
return byteOffset(i);
|
||||
}
|
||||
|
||||
private static long byteOffset(int i) {
|
||||
return ((long) i << shift) + base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AtomicLongArray of given length.
|
||||
* Creates a new AtomicLongArray of the given length, with all
|
||||
* elements initially zero.
|
||||
*
|
||||
* @param length the length of the array
|
||||
*/
|
||||
public AtomicLongArray(int length) {
|
||||
array = new long[length];
|
||||
// must perform at least one volatile write to conform to JMM
|
||||
if (length > 0)
|
||||
unsafe.putLongVolatile(array, rawIndex(0), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,17 +88,8 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @throws NullPointerException if array is null
|
||||
*/
|
||||
public AtomicLongArray(long[] array) {
|
||||
if (array == null)
|
||||
throw new NullPointerException();
|
||||
int length = array.length;
|
||||
this.array = new long[length];
|
||||
if (length > 0) {
|
||||
int last = length-1;
|
||||
for (int i = 0; i < last; ++i)
|
||||
this.array[i] = array[i];
|
||||
// Do the last write as volatile
|
||||
unsafe.putLongVolatile(this.array, rawIndex(last), array[last]);
|
||||
}
|
||||
// Visibility guaranteed by final field guarantees
|
||||
this.array = array.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,7 +108,11 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the current value
|
||||
*/
|
||||
public final long get(int i) {
|
||||
return unsafe.getLongVolatile(array, rawIndex(i));
|
||||
return getRaw(checkedByteOffset(i));
|
||||
}
|
||||
|
||||
private long getRaw(long offset) {
|
||||
return unsafe.getLongVolatile(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +122,7 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @param newValue the new value
|
||||
*/
|
||||
public final void set(int i, long newValue) {
|
||||
unsafe.putLongVolatile(array, rawIndex(i), newValue);
|
||||
unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,7 +133,7 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @since 1.6
|
||||
*/
|
||||
public final void lazySet(int i, long newValue) {
|
||||
unsafe.putOrderedLong(array, rawIndex(i), newValue);
|
||||
unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
|
||||
}
|
||||
|
||||
|
||||
@ -142,16 +146,17 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final long getAndSet(int i, long newValue) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
if (compareAndSet(i, current, newValue))
|
||||
long current = getRaw(offset);
|
||||
if (compareAndSetRaw(offset, current, newValue))
|
||||
return current;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically sets the value to the given updated value
|
||||
* if the current value {@code ==} the expected value.
|
||||
* Atomically sets the element at position {@code i} to the given
|
||||
* updated value if the current value {@code ==} the expected value.
|
||||
*
|
||||
* @param i the index
|
||||
* @param expect the expected value
|
||||
@ -160,13 +165,16 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* the actual value was not equal to the expected value.
|
||||
*/
|
||||
public final boolean compareAndSet(int i, long expect, long update) {
|
||||
return unsafe.compareAndSwapLong(array, rawIndex(i),
|
||||
expect, update);
|
||||
return compareAndSetRaw(checkedByteOffset(i), expect, update);
|
||||
}
|
||||
|
||||
private boolean compareAndSetRaw(long offset, long expect, long update) {
|
||||
return unsafe.compareAndSwapLong(array, offset, expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically sets the value to the given updated value
|
||||
* if the current value {@code ==} the expected value.
|
||||
* Atomically sets the element at position {@code i} to the given
|
||||
* updated value if the current value {@code ==} the expected value.
|
||||
*
|
||||
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
|
||||
* and does not provide ordering guarantees, so is only rarely an
|
||||
@ -188,12 +196,7 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final long getAndIncrement(int i) {
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
long next = current + 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return current;
|
||||
}
|
||||
return getAndAdd(i, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,12 +206,7 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final long getAndDecrement(int i) {
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
long next = current - 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return current;
|
||||
}
|
||||
return getAndAdd(i, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,10 +217,10 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final long getAndAdd(int i, long delta) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
long next = current + delta;
|
||||
if (compareAndSet(i, current, next))
|
||||
long current = getRaw(offset);
|
||||
if (compareAndSetRaw(offset, current, current + delta))
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@ -234,12 +232,7 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the updated value
|
||||
*/
|
||||
public final long incrementAndGet(int i) {
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
long next = current + 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return next;
|
||||
}
|
||||
return addAndGet(i, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,12 +242,7 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the updated value
|
||||
*/
|
||||
public final long decrementAndGet(int i) {
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
long next = current - 1;
|
||||
if (compareAndSet(i, current, next))
|
||||
return next;
|
||||
}
|
||||
return addAndGet(i, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -265,22 +253,32 @@ public class AtomicLongArray implements java.io.Serializable {
|
||||
* @return the updated value
|
||||
*/
|
||||
public long addAndGet(int i, long delta) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
long current = get(i);
|
||||
long current = getRaw(offset);
|
||||
long next = current + delta;
|
||||
if (compareAndSet(i, current, next))
|
||||
if (compareAndSetRaw(offset, current, next))
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the String representation of the current values of array.
|
||||
* @return the String representation of the current values of array.
|
||||
* @return the String representation of the current values of array
|
||||
*/
|
||||
public String toString() {
|
||||
if (array.length > 0) // force volatile read
|
||||
get(0);
|
||||
return Arrays.toString(array);
|
||||
int iMax = array.length - 1;
|
||||
if (iMax == -1)
|
||||
return "[]";
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
b.append(getRaw(byteOffset(i)));
|
||||
if (i == iMax)
|
||||
return b.append(']').toString();
|
||||
b.append(',').append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ package java.util.concurrent.atomic;
|
||||
/**
|
||||
* An {@code AtomicMarkableReference} maintains an object reference
|
||||
* along with a mark bit, that can be updated atomically.
|
||||
* <p>
|
||||
* <p> Implementation note. This implementation maintains markable
|
||||
*
|
||||
* <p>Implementation note: This implementation maintains markable
|
||||
* references by creating internal objects representing "boxed"
|
||||
* [reference, boolean] pairs.
|
||||
*
|
||||
@ -47,17 +47,21 @@ package java.util.concurrent.atomic;
|
||||
* @author Doug Lea
|
||||
* @param <V> The type of object referred to by this reference
|
||||
*/
|
||||
public class AtomicMarkableReference<V> {
|
||||
public class AtomicMarkableReference<V> {
|
||||
|
||||
private static class ReferenceBooleanPair<T> {
|
||||
private final T reference;
|
||||
private final boolean bit;
|
||||
ReferenceBooleanPair(T r, boolean i) {
|
||||
reference = r; bit = i;
|
||||
private static class Pair<T> {
|
||||
final T reference;
|
||||
final boolean mark;
|
||||
private Pair(T reference, boolean mark) {
|
||||
this.reference = reference;
|
||||
this.mark = mark;
|
||||
}
|
||||
static <T> Pair<T> of(T reference, boolean mark) {
|
||||
return new Pair<T>(reference, mark);
|
||||
}
|
||||
}
|
||||
|
||||
private final AtomicReference<ReferenceBooleanPair<V>> atomicRef;
|
||||
private volatile Pair<V> pair;
|
||||
|
||||
/**
|
||||
* Creates a new {@code AtomicMarkableReference} with the given
|
||||
@ -67,7 +71,7 @@ public class AtomicMarkableReference<V> {
|
||||
* @param initialMark the initial mark
|
||||
*/
|
||||
public AtomicMarkableReference(V initialRef, boolean initialMark) {
|
||||
atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark));
|
||||
pair = Pair.of(initialRef, initialMark);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,7 +80,7 @@ public class AtomicMarkableReference<V> {
|
||||
* @return the current value of the reference
|
||||
*/
|
||||
public V getReference() {
|
||||
return atomicRef.get().reference;
|
||||
return pair.reference;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -85,7 +89,7 @@ public class AtomicMarkableReference<V> {
|
||||
* @return the current value of the mark
|
||||
*/
|
||||
public boolean isMarked() {
|
||||
return atomicRef.get().bit;
|
||||
return pair.mark;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,9 +101,9 @@ public class AtomicMarkableReference<V> {
|
||||
* @return the current value of the reference
|
||||
*/
|
||||
public V get(boolean[] markHolder) {
|
||||
ReferenceBooleanPair<V> p = atomicRef.get();
|
||||
markHolder[0] = p.bit;
|
||||
return p.reference;
|
||||
Pair<V> pair = this.pair;
|
||||
markHolder[0] = pair.mark;
|
||||
return pair.reference;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,13 +126,8 @@ public class AtomicMarkableReference<V> {
|
||||
V newReference,
|
||||
boolean expectedMark,
|
||||
boolean newMark) {
|
||||
ReferenceBooleanPair<V> current = atomicRef.get();
|
||||
return expectedReference == current.reference &&
|
||||
expectedMark == current.bit &&
|
||||
((newReference == current.reference && newMark == current.bit) ||
|
||||
atomicRef.weakCompareAndSet(current,
|
||||
new ReferenceBooleanPair<V>(newReference,
|
||||
newMark)));
|
||||
return compareAndSet(expectedReference, newReference,
|
||||
expectedMark, newMark);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,13 +146,13 @@ public class AtomicMarkableReference<V> {
|
||||
V newReference,
|
||||
boolean expectedMark,
|
||||
boolean newMark) {
|
||||
ReferenceBooleanPair<V> current = atomicRef.get();
|
||||
return expectedReference == current.reference &&
|
||||
expectedMark == current.bit &&
|
||||
((newReference == current.reference && newMark == current.bit) ||
|
||||
atomicRef.compareAndSet(current,
|
||||
new ReferenceBooleanPair<V>(newReference,
|
||||
newMark)));
|
||||
Pair<V> current = pair;
|
||||
return
|
||||
expectedReference == current.reference &&
|
||||
expectedMark == current.mark &&
|
||||
((newReference == current.reference &&
|
||||
newMark == current.mark) ||
|
||||
casPair(current, Pair.of(newReference, newMark)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,9 +162,9 @@ public class AtomicMarkableReference<V> {
|
||||
* @param newMark the new value for the mark
|
||||
*/
|
||||
public void set(V newReference, boolean newMark) {
|
||||
ReferenceBooleanPair<V> current = atomicRef.get();
|
||||
if (newReference != current.reference || newMark != current.bit)
|
||||
atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark));
|
||||
Pair<V> current = pair;
|
||||
if (newReference != current.reference || newMark != current.mark)
|
||||
this.pair = Pair.of(newReference, newMark);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,11 +181,32 @@ public class AtomicMarkableReference<V> {
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean attemptMark(V expectedReference, boolean newMark) {
|
||||
ReferenceBooleanPair<V> current = atomicRef.get();
|
||||
return expectedReference == current.reference &&
|
||||
(newMark == current.bit ||
|
||||
atomicRef.compareAndSet
|
||||
(current, new ReferenceBooleanPair<V>(expectedReference,
|
||||
newMark)));
|
||||
Pair<V> current = pair;
|
||||
return
|
||||
expectedReference == current.reference &&
|
||||
(newMark == current.mark ||
|
||||
casPair(current, Pair.of(expectedReference, newMark)));
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long pairOffset =
|
||||
objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
|
||||
|
||||
private boolean casPair(Pair<V> cmp, Pair<V> val) {
|
||||
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
|
||||
}
|
||||
|
||||
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
|
||||
String field, Class<?> klazz) {
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Convert Exception to corresponding Error
|
||||
NoSuchFieldError error = new NoSuchFieldError(field);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,24 +51,35 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
|
||||
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||
private static final int base = unsafe.arrayBaseOffset(Object[].class);
|
||||
private static final int scale = unsafe.arrayIndexScale(Object[].class);
|
||||
private static final int shift;
|
||||
private final Object[] array;
|
||||
|
||||
private long rawIndex(int i) {
|
||||
static {
|
||||
int scale = unsafe.arrayIndexScale(Object[].class);
|
||||
if ((scale & (scale - 1)) != 0)
|
||||
throw new Error("data type scale not a power of two");
|
||||
shift = 31 - Integer.numberOfLeadingZeros(scale);
|
||||
}
|
||||
|
||||
private long checkedByteOffset(int i) {
|
||||
if (i < 0 || i >= array.length)
|
||||
throw new IndexOutOfBoundsException("index " + i);
|
||||
return base + (long) i * scale;
|
||||
|
||||
return byteOffset(i);
|
||||
}
|
||||
|
||||
private static long byteOffset(int i) {
|
||||
return ((long) i << shift) + base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AtomicReferenceArray of given length.
|
||||
* Creates a new AtomicReferenceArray of the given length, with all
|
||||
* elements initially null.
|
||||
*
|
||||
* @param length the length of the array
|
||||
*/
|
||||
public AtomicReferenceArray(int length) {
|
||||
array = new Object[length];
|
||||
// must perform at least one volatile write to conform to JMM
|
||||
if (length > 0)
|
||||
unsafe.putObjectVolatile(array, rawIndex(0), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,18 +90,8 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
* @throws NullPointerException if array is null
|
||||
*/
|
||||
public AtomicReferenceArray(E[] array) {
|
||||
if (array == null)
|
||||
throw new NullPointerException();
|
||||
int length = array.length;
|
||||
this.array = new Object[length];
|
||||
if (length > 0) {
|
||||
int last = length-1;
|
||||
for (int i = 0; i < last; ++i)
|
||||
this.array[i] = array[i];
|
||||
// Do the last write as volatile
|
||||
E e = array[last];
|
||||
unsafe.putObjectVolatile(this.array, rawIndex(last), e);
|
||||
}
|
||||
// Visibility guaranteed by final field guarantees
|
||||
this.array = array.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,7 +110,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
* @return the current value
|
||||
*/
|
||||
public final E get(int i) {
|
||||
return (E) unsafe.getObjectVolatile(array, rawIndex(i));
|
||||
return getRaw(checkedByteOffset(i));
|
||||
}
|
||||
|
||||
private E getRaw(long offset) {
|
||||
return (E) unsafe.getObjectVolatile(array, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,7 +124,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
* @param newValue the new value
|
||||
*/
|
||||
public final void set(int i, E newValue) {
|
||||
unsafe.putObjectVolatile(array, rawIndex(i), newValue);
|
||||
unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +135,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
* @since 1.6
|
||||
*/
|
||||
public final void lazySet(int i, E newValue) {
|
||||
unsafe.putOrderedObject(array, rawIndex(i), newValue);
|
||||
unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
|
||||
}
|
||||
|
||||
|
||||
@ -143,9 +148,10 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
* @return the previous value
|
||||
*/
|
||||
public final E getAndSet(int i, E newValue) {
|
||||
long offset = checkedByteOffset(i);
|
||||
while (true) {
|
||||
E current = get(i);
|
||||
if (compareAndSet(i, current, newValue))
|
||||
E current = (E) getRaw(offset);
|
||||
if (compareAndSetRaw(offset, current, newValue))
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@ -153,6 +159,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
/**
|
||||
* Atomically sets the element at position {@code i} to the given
|
||||
* updated value if the current value {@code ==} the expected value.
|
||||
*
|
||||
* @param i the index
|
||||
* @param expect the expected value
|
||||
* @param update the new value
|
||||
@ -160,8 +167,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
* the actual value was not equal to the expected value.
|
||||
*/
|
||||
public final boolean compareAndSet(int i, E expect, E update) {
|
||||
return unsafe.compareAndSwapObject(array, rawIndex(i),
|
||||
expect, update);
|
||||
return compareAndSetRaw(checkedByteOffset(i), expect, update);
|
||||
}
|
||||
|
||||
private boolean compareAndSetRaw(long offset, E expect, E update) {
|
||||
return unsafe.compareAndSwapObject(array, offset, expect, update);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,12 +193,21 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
|
||||
|
||||
/**
|
||||
* Returns the String representation of the current values of array.
|
||||
* @return the String representation of the current values of array.
|
||||
* @return the String representation of the current values of array
|
||||
*/
|
||||
public String toString() {
|
||||
if (array.length > 0) // force volatile read
|
||||
get(0);
|
||||
return Arrays.toString(array);
|
||||
int iMax = array.length - 1;
|
||||
if (iMax == -1)
|
||||
return "[]";
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
b.append(getRaw(byteOffset(i)));
|
||||
if (i == iMax)
|
||||
return b.append(']').toString();
|
||||
b.append(',').append(' ');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ package java.util.concurrent.atomic;
|
||||
* An {@code AtomicStampedReference} maintains an object reference
|
||||
* along with an integer "stamp", that can be updated atomically.
|
||||
*
|
||||
* <p> Implementation note. This implementation maintains stamped
|
||||
* <p>Implementation note: This implementation maintains stamped
|
||||
* references by creating internal objects representing "boxed"
|
||||
* [reference, integer] pairs.
|
||||
*
|
||||
@ -47,17 +47,21 @@ package java.util.concurrent.atomic;
|
||||
* @author Doug Lea
|
||||
* @param <V> The type of object referred to by this reference
|
||||
*/
|
||||
public class AtomicStampedReference<V> {
|
||||
public class AtomicStampedReference<V> {
|
||||
|
||||
private static class ReferenceIntegerPair<T> {
|
||||
private final T reference;
|
||||
private final int integer;
|
||||
ReferenceIntegerPair(T r, int i) {
|
||||
reference = r; integer = i;
|
||||
private static class Pair<T> {
|
||||
final T reference;
|
||||
final int stamp;
|
||||
private Pair(T reference, int stamp) {
|
||||
this.reference = reference;
|
||||
this.stamp = stamp;
|
||||
}
|
||||
static <T> Pair<T> of(T reference, int stamp) {
|
||||
return new Pair<T>(reference, stamp);
|
||||
}
|
||||
}
|
||||
|
||||
private final AtomicReference<ReferenceIntegerPair<V>> atomicRef;
|
||||
private volatile Pair<V> pair;
|
||||
|
||||
/**
|
||||
* Creates a new {@code AtomicStampedReference} with the given
|
||||
@ -67,8 +71,7 @@ public class AtomicStampedReference<V> {
|
||||
* @param initialStamp the initial stamp
|
||||
*/
|
||||
public AtomicStampedReference(V initialRef, int initialStamp) {
|
||||
atomicRef = new AtomicReference<ReferenceIntegerPair<V>>
|
||||
(new ReferenceIntegerPair<V>(initialRef, initialStamp));
|
||||
pair = Pair.of(initialRef, initialStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,7 +80,7 @@ public class AtomicStampedReference<V> {
|
||||
* @return the current value of the reference
|
||||
*/
|
||||
public V getReference() {
|
||||
return atomicRef.get().reference;
|
||||
return pair.reference;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,7 +89,7 @@ public class AtomicStampedReference<V> {
|
||||
* @return the current value of the stamp
|
||||
*/
|
||||
public int getStamp() {
|
||||
return atomicRef.get().integer;
|
||||
return pair.stamp;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,9 +101,9 @@ public class AtomicStampedReference<V> {
|
||||
* @return the current value of the reference
|
||||
*/
|
||||
public V get(int[] stampHolder) {
|
||||
ReferenceIntegerPair<V> p = atomicRef.get();
|
||||
stampHolder[0] = p.integer;
|
||||
return p.reference;
|
||||
Pair<V> pair = this.pair;
|
||||
stampHolder[0] = pair.stamp;
|
||||
return pair.reference;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,18 +122,12 @@ public class AtomicStampedReference<V> {
|
||||
* @param newStamp the new value for the stamp
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean weakCompareAndSet(V expectedReference,
|
||||
V newReference,
|
||||
int expectedStamp,
|
||||
int newStamp) {
|
||||
ReferenceIntegerPair<V> current = atomicRef.get();
|
||||
return expectedReference == current.reference &&
|
||||
expectedStamp == current.integer &&
|
||||
((newReference == current.reference &&
|
||||
newStamp == current.integer) ||
|
||||
atomicRef.weakCompareAndSet(current,
|
||||
new ReferenceIntegerPair<V>(newReference,
|
||||
newStamp)));
|
||||
public boolean weakCompareAndSet(V expectedReference,
|
||||
V newReference,
|
||||
int expectedStamp,
|
||||
int newStamp) {
|
||||
return compareAndSet(expectedReference, newReference,
|
||||
expectedStamp, newStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,18 +142,17 @@ public class AtomicStampedReference<V> {
|
||||
* @param newStamp the new value for the stamp
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean compareAndSet(V expectedReference,
|
||||
V newReference,
|
||||
int expectedStamp,
|
||||
int newStamp) {
|
||||
ReferenceIntegerPair<V> current = atomicRef.get();
|
||||
return expectedReference == current.reference &&
|
||||
expectedStamp == current.integer &&
|
||||
public boolean compareAndSet(V expectedReference,
|
||||
V newReference,
|
||||
int expectedStamp,
|
||||
int newStamp) {
|
||||
Pair<V> current = pair;
|
||||
return
|
||||
expectedReference == current.reference &&
|
||||
expectedStamp == current.stamp &&
|
||||
((newReference == current.reference &&
|
||||
newStamp == current.integer) ||
|
||||
atomicRef.compareAndSet(current,
|
||||
new ReferenceIntegerPair<V>(newReference,
|
||||
newStamp)));
|
||||
newStamp == current.stamp) ||
|
||||
casPair(current, Pair.of(newReference, newStamp)));
|
||||
}
|
||||
|
||||
|
||||
@ -167,9 +163,9 @@ public class AtomicStampedReference<V> {
|
||||
* @param newStamp the new value for the stamp
|
||||
*/
|
||||
public void set(V newReference, int newStamp) {
|
||||
ReferenceIntegerPair<V> current = atomicRef.get();
|
||||
if (newReference != current.reference || newStamp != current.integer)
|
||||
atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp));
|
||||
Pair<V> current = pair;
|
||||
if (newReference != current.reference || newStamp != current.stamp)
|
||||
this.pair = Pair.of(newReference, newStamp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -186,11 +182,32 @@ public class AtomicStampedReference<V> {
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean attemptStamp(V expectedReference, int newStamp) {
|
||||
ReferenceIntegerPair<V> current = atomicRef.get();
|
||||
return expectedReference == current.reference &&
|
||||
(newStamp == current.integer ||
|
||||
atomicRef.compareAndSet(current,
|
||||
new ReferenceIntegerPair<V>(expectedReference,
|
||||
newStamp)));
|
||||
Pair<V> current = pair;
|
||||
return
|
||||
expectedReference == current.reference &&
|
||||
(newStamp == current.stamp ||
|
||||
casPair(current, Pair.of(expectedReference, newStamp)));
|
||||
}
|
||||
|
||||
// Unsafe mechanics
|
||||
|
||||
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
|
||||
private static final long pairOffset =
|
||||
objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
|
||||
|
||||
private boolean casPair(Pair<V> cmp, Pair<V> val) {
|
||||
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
|
||||
}
|
||||
|
||||
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
|
||||
String field, Class<?> klazz) {
|
||||
try {
|
||||
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Convert Exception to corresponding Error
|
||||
NoSuchFieldError error = new NoSuchFieldError(field);
|
||||
error.initCause(e);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,18 +308,21 @@ public interface Condition {
|
||||
* condition still does not hold. Typical uses of this method take
|
||||
* the following form:
|
||||
*
|
||||
* <pre>
|
||||
* synchronized boolean aMethod(long timeout, TimeUnit unit) {
|
||||
* long nanosTimeout = unit.toNanos(timeout);
|
||||
* while (!conditionBeingWaitedFor) {
|
||||
* if (nanosTimeout > 0)
|
||||
* nanosTimeout = theCondition.awaitNanos(nanosTimeout);
|
||||
* else
|
||||
* return false;
|
||||
* <pre> {@code
|
||||
* boolean aMethod(long timeout, TimeUnit unit) {
|
||||
* long nanos = unit.toNanos(timeout);
|
||||
* lock.lock();
|
||||
* try {
|
||||
* while (!conditionBeingWaitedFor()) {
|
||||
* if (nanos <= 0L)
|
||||
* return false;
|
||||
* nanos = theCondition.awaitNanos(nanos);
|
||||
* }
|
||||
* // ...
|
||||
* } finally {
|
||||
* lock.unlock();
|
||||
* }
|
||||
* // ...
|
||||
* }
|
||||
* </pre>
|
||||
* }}</pre>
|
||||
*
|
||||
* <p> Design note: This method requires a nanosecond argument so
|
||||
* as to avoid truncation errors in reporting remaining times.
|
||||
@ -408,18 +411,21 @@ public interface Condition {
|
||||
*
|
||||
* <p>The return value indicates whether the deadline has elapsed,
|
||||
* which can be used as follows:
|
||||
* <pre>
|
||||
* synchronized boolean aMethod(Date deadline) {
|
||||
* <pre> {@code
|
||||
* boolean aMethod(Date deadline) {
|
||||
* boolean stillWaiting = true;
|
||||
* while (!conditionBeingWaitedFor) {
|
||||
* if (stillWaiting)
|
||||
* stillWaiting = theCondition.awaitUntil(deadline);
|
||||
* else
|
||||
* return false;
|
||||
* lock.lock();
|
||||
* try {
|
||||
* while (!conditionBeingWaitedFor()) {
|
||||
* if (!stillWaiting)
|
||||
* return false;
|
||||
* stillWaiting = theCondition.awaitUntil(deadline);
|
||||
* }
|
||||
* // ...
|
||||
* } finally {
|
||||
* lock.unlock();
|
||||
* }
|
||||
* // ...
|
||||
* }
|
||||
* </pre>
|
||||
* }}</pre>
|
||||
*
|
||||
* <p><b>Implementation Considerations</b>
|
||||
*
|
||||
@ -450,6 +456,15 @@ public interface Condition {
|
||||
* <p>If any threads are waiting on this condition then one
|
||||
* is selected for waking up. That thread must then re-acquire the
|
||||
* lock before returning from {@code await}.
|
||||
*
|
||||
* <p><b>Implementation Considerations</b>
|
||||
*
|
||||
* <p>An implementation may (and typically does) require that the
|
||||
* current thread hold the lock associated with this {@code
|
||||
* Condition} when this method is called. Implementations must
|
||||
* document this precondition and any actions taken if the lock is
|
||||
* not held. Typically, an exception such as {@link
|
||||
* IllegalMonitorStateException} will be thrown.
|
||||
*/
|
||||
void signal();
|
||||
|
||||
@ -459,6 +474,15 @@ public interface Condition {
|
||||
* <p>If any threads are waiting on this condition then they are
|
||||
* all woken up. Each thread must re-acquire the lock before it can
|
||||
* return from {@code await}.
|
||||
*
|
||||
* <p><b>Implementation Considerations</b>
|
||||
*
|
||||
* <p>An implementation may (and typically does) require that the
|
||||
* current thread hold the lock associated with this {@code
|
||||
* Condition} when this method is called. Implementations must
|
||||
* document this precondition and any actions taken if the lock is
|
||||
* not held. Typically, an exception such as {@link
|
||||
* IllegalMonitorStateException} will be thrown.
|
||||
*/
|
||||
void signalAll();
|
||||
}
|
||||
|
@ -1426,7 +1426,7 @@ public class Logger {
|
||||
// we didn't have a previous parent
|
||||
ref = manager.new LoggerWeakRef(this);
|
||||
}
|
||||
ref.setParentRef(new WeakReference<>(parent));
|
||||
ref.setParentRef(new WeakReference<Logger>(parent));
|
||||
parent.kids.add(ref);
|
||||
|
||||
// As a result of the reparenting, the effective level
|
||||
|
@ -107,7 +107,7 @@ public abstract class CompiledScript {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>ScriptEngine</code> wbose <code>compile</code> method created this <code>CompiledScript</code>.
|
||||
* Returns the <code>ScriptEngine</code> whose <code>compile</code> method created this <code>CompiledScript</code>.
|
||||
* The <code>CompiledScript</code> will execute in this engine.
|
||||
*
|
||||
* @return The <code>ScriptEngine</code> that created this <code>CompiledScript</code>
|
||||
|
@ -329,7 +329,7 @@ public final class PrivateCredentialPermission extends Permission {
|
||||
throw new IllegalArgumentException("invalid empty name");
|
||||
}
|
||||
|
||||
ArrayList<CredOwner> pList = new ArrayList<CredOwner>();
|
||||
ArrayList<CredOwner> pList = new ArrayList<>();
|
||||
StringTokenizer tokenizer = new StringTokenizer(name, " ", true);
|
||||
String principalClass = null;
|
||||
String principalName = null;
|
||||
|
@ -48,7 +48,7 @@ public class SubjectDomainCombiner implements java.security.DomainCombiner {
|
||||
|
||||
private Subject subject;
|
||||
private WeakKeyValueMap<ProtectionDomain, ProtectionDomain> cachedPDs =
|
||||
new WeakKeyValueMap<ProtectionDomain, ProtectionDomain>();
|
||||
new WeakKeyValueMap<>();
|
||||
private Set<Principal> principalSet;
|
||||
private Principal[] principals;
|
||||
|
||||
|
@ -361,7 +361,7 @@ final class KrbDelegationPermissionCollection extends PermissionCollection
|
||||
// Don't call out.defaultWriteObject()
|
||||
|
||||
// Write out Vector
|
||||
Vector<Permission> permissions = new Vector<Permission>(perms.size());
|
||||
Vector<Permission> permissions = new Vector<>(perms.size());
|
||||
|
||||
synchronized (this) {
|
||||
permissions.addAll(perms);
|
||||
|
@ -569,7 +569,7 @@ final class KrbServicePermissionCollection extends PermissionCollection
|
||||
// Don't call out.defaultWriteObject()
|
||||
|
||||
// Write out Vector
|
||||
Vector<Permission> permissions = new Vector<Permission>(perms.size());
|
||||
Vector<Permission> permissions = new Vector<>(perms.size());
|
||||
|
||||
synchronized (this) {
|
||||
permissions.addAll(perms);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2011, 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
|
||||
@ -25,9 +25,7 @@
|
||||
|
||||
package javax.sql.rowset.serial;
|
||||
|
||||
import java.sql.*;
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.lang.reflect.*;
|
||||
import javax.sql.rowset.RowSetWarning;
|
||||
|
||||
@ -51,7 +49,7 @@ public class SerialJavaObject implements Serializable, Cloneable {
|
||||
/**
|
||||
* Placeholder for object to be serialized.
|
||||
*/
|
||||
private Object obj;
|
||||
private final Object obj;
|
||||
|
||||
|
||||
/**
|
||||
@ -64,8 +62,7 @@ public class SerialJavaObject implements Serializable, Cloneable {
|
||||
* <p>
|
||||
*
|
||||
* @param obj the Java <code>Object</code> to be serialized
|
||||
* @throws SerialException if the object is found
|
||||
* to be unserializable
|
||||
* @throws SerialException if the object is found not to be serializable
|
||||
*/
|
||||
public SerialJavaObject(Object obj) throws SerialException {
|
||||
|
||||
@ -74,16 +71,11 @@ public class SerialJavaObject implements Serializable, Cloneable {
|
||||
|
||||
|
||||
// get Class. Object instance should always be available
|
||||
Class c = obj.getClass();
|
||||
Class<?> c = obj.getClass();
|
||||
|
||||
// determine if object implements Serializable i/f
|
||||
boolean serializableImpl = false;
|
||||
Class[] theIf = c.getInterfaces();
|
||||
for (int i = 0; i < theIf.length; i++) {
|
||||
String ifName = theIf[i].getName();
|
||||
if (ifName == "java.io.Serializable") {
|
||||
serializableImpl = true;
|
||||
}
|
||||
if (!(obj instanceof java.io.Serializable)) {
|
||||
setWarning(new RowSetWarning("Warning, the object passed to the constructor does not implement Serializable"));
|
||||
}
|
||||
|
||||
// can only determine public fields (obviously). If
|
||||
@ -93,22 +85,14 @@ public class SerialJavaObject implements Serializable, Cloneable {
|
||||
|
||||
boolean anyStaticFields = false;
|
||||
fields = c.getFields();
|
||||
//fields = new Object[field.length];
|
||||
|
||||
for (int i = 0; i < fields.length; i++ ) {
|
||||
if ( fields[i].getModifiers() == Modifier.STATIC ) {
|
||||
anyStaticFields = true;
|
||||
}
|
||||
//fields[i] = field[i].get(obj);
|
||||
}
|
||||
try {
|
||||
if (!(serializableImpl)) {
|
||||
throw new RowSetWarning("Test");
|
||||
}
|
||||
} catch (RowSetWarning w) {
|
||||
setWarning(w);
|
||||
}
|
||||
|
||||
|
||||
if (anyStaticFields) {
|
||||
throw new SerialException("Located static fields in " +
|
||||
"object instance. Cannot serialize");
|
||||
@ -139,11 +123,8 @@ public class SerialJavaObject implements Serializable, Cloneable {
|
||||
*/
|
||||
public Field[] getFields() throws SerialException {
|
||||
if (fields != null) {
|
||||
Class c = this.obj.getClass();
|
||||
//the following has to be commented before mustang integration
|
||||
//return c.getFields();
|
||||
//the following has to be uncommented before mustang integration
|
||||
return sun.reflect.misc.FieldUtil.getFields(c);
|
||||
Class<?> c = this.obj.getClass();
|
||||
return c.getFields();
|
||||
} else {
|
||||
throw new SerialException("SerialJavaObject does not contain" +
|
||||
" a serialized object instance");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user