`
mikab
  • 浏览: 17808 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

JDK1.6.0_20下一个应该是BUG的运行时问题

阅读更多
最近自己打算实现一个比较原始但是可以自动释放的锁的管理类,基本想法是根据一个对象id(整数)得到一个锁,同一时刻只能有一个锁的实例对应该id,并且当内存内没有被外部对象持有该id对应的锁时,无论该锁是不是锁定状态该锁的实例都可以被自动释放掉。

代码大概如下:
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class AutoReleaseLock implements Lock {
	private static transient Map<Integer, Lock> objectLocks = new WeakHashMap<Integer, Lock>(32);

	public static synchronized Lock getObjectLock(int id) {
		//不能使用JDK自动装箱的功能,128以内的数会被JDK缓存住
		Integer key = new Integer(id);
		Lock lock = objectLocks.get(key);
		if (lock == null) {
			lock = new ReentrantLock();
			objectLocks.put(key, lock);
		} else {
			//在导出的lock实现中使用map中的key,防止该锁存在时该对象被回收
			for (Map.Entry<Integer, Lock> entry : objectLocks.entrySet()) {
				if (key.equals(entry.getKey())) {
					key = entry.getKey();
				}
			}
		}
		return new AutoReleaseLock(key, lock);
	}

	Integer objectID;
	Lock lockImplement;

	private AutoReleaseLock(Integer id, Lock impl) {
		this.objectID = id;
		lockImplement = impl;
	}

	public void lock() {
		lockImplement.lock();

	}

	public void lockInterruptibly() throws InterruptedException {
		lockImplement.lockInterruptibly();

	}

	public Condition newCondition() {
		return lockImplement.newCondition();
	}

	public boolean tryLock() {
		return lockImplement.tryLock();
	}

	public boolean tryLock(long time, TimeUnit unit)
			throws InterruptedException {
		return lockImplement.tryLock(time, unit);
	}

	public void unlock() {
		lockImplement.unlock();
	}
}


然后我写了个测试:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.locks.Lock;

import junit.framework.TestCase;

public class AutoReleaseLockTest extends TestCase {
	
	public void testObjectLock() throws Exception {
		ExecutorService service = Executors.newCachedThreadPool();
		
		Lock lock = AutoReleaseLock.getObjectLock(1);
		assertNotNull(lock);
		lock.lock();

		System.gc();
		Thread.sleep(1);
		System.gc();

		// JDK1.6 BUG在这里
		//System.err.println(lock);
		Future<?> feature = service.submit(new Runnable() {
			public void run() {

				Lock lock2 = AutoReleaseLock.getObjectLock(1);
				assertEquals(lock2.tryLock(), false);
			}
		});
		feature.get();
		Thread.sleep(100);

		lock = AutoReleaseLock.getObjectLock(1);
		assertNotNull(lock);

		System.gc();
		Thread.sleep(1);
		System.gc();
		feature = service.submit(new Runnable() {
			public void run() {
				Lock lock2 = AutoReleaseLock.getObjectLock(1);
				assertEquals(lock2.tryLock(), false);
			}
		});
		feature.get();

		lock.unlock();
		feature = service.submit(new Runnable() {
			public void run() {
				Lock lock2 = AutoReleaseLock.getObjectLock(1);
				assertEquals(lock2.tryLock(), true);
				lock2.unlock();
			}
		});
		feature.get();


		lock.lock();
		lock = null;
		System.gc();
		//GC一定要来哦
		Map<Integer, byte[][]> temp = new HashMap<Integer, byte[][]>();
		for (int i = 0; i < 64; i++) {
			temp.put(new Integer(i), new byte[1024][1024]);
		}
		Thread.sleep(1);
		System.gc();
		feature = service.submit(new Runnable() {
			public void run() {
				Lock lock2 = AutoReleaseLock.getObjectLock(1);
				assertNotNull(lock2);
				assertTrue(lock2.tryLock());
				lock2.unlock();
			}
		});
		feature.get();
		System.gc();
		//GC一定要来哦
		for (int i = 0; i < 64; i++) {
			temp.put(new Integer(i), new byte[1024][1024]);
		}
		Thread.sleep(1);
		System.gc();

		//release
		for (int i = 0; i < 100000; i++) {
			lock = AutoReleaseLock.getObjectLock(i);
			try {
				assertTrue(lock.tryLock());
			} finally {
				lock.unlock();
			}
		}
	}
	
	public void test10Times()throws Exception{
		System.err.println(System.getProperties());
		for(int i=0;i<10;i++){
			System.err.println(i);
			testObjectLock();
		}
	}
}

请注意,测试类的第24行(System.err.println(lock);)最开始是没有的,因为最开始开发是在JDK1.5下开发,测试一切正常。突然有一天我们升级到JDK1.6,居然发现我们的测试用例跑不过了。经过百般的探索,发现只要运行第3遍testObjectLock,test类的第29行处就会报错,后台打印输出居然发现objectLocks 是空的,也就是说objectLocks 里对象被释放掉了,那么最外部的lock对象呢?

于是我加上了第24行,这样在JDK1.6下测试也顺利通过了。但是一旦把第24行注掉,test10Times中运行第3次testObjectLock时就会在29行处出错。

我初步怀疑是JDK的JIT在进行优化时,认为在29行处lock所指向实例已经没人使用就释放掉了,而objectLocks 也因此被清空,导致test通不过。欢迎各位的高见。

我的操作系统是windows7 32位好像是英文版,改成的中文界面,JDK 1.6.0-20,
{java.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=C:\Program Files\Java\jdk1.6.0_20\jre\bin, java.vm.version=16.3-b01, java.vm.vendor=Sun Microsystems Inc., java.vendor.url=http://java.sun.com/, path.separator=;, java.vm.name=Java HotSpot(TM) Client VM, file.encoding.pkg=sun.io, sun.java.launcher=SUN_STANDARD, user.country=CN, sun.os.patch.level=, java.vm.specification.name=Java Virtual Machine Specification, user.dir=D:\workspace\sources\csvformater, java.runtime.version=1.6.0_20-b02, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Program Files\Java\jdk1.6.0_20\jre\lib\endorsed, os.arch=x86, java.io.tmpdir=C:\Users\pengzy\AppData\Local\Temp\, line.separator=
, java.vm.specification.vendor=Sun Microsystems Inc., user.variant=, os.name=Windows 7, sun.jnu.encoding=GBK, java.library.path=..., java.specification.name=Java Platform API Specification, java.class.version=50.0, sun.management.compiler=HotSpot Client Compiler, os.version=6.1, user.home=C:\Users\pengzy, user.timezone=, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=GBK, java.specification.version=1.6, java.class.path=D:\workspace\sources\csvformater\bin;D:\workspace\sources\csvformater\lib\jxl-2.5.7.jar;D:\HCIT_SDK_3.4\eclipse\plugins\org.junit_3.8.2.v20080602-1318\junit.jar;/D:/HCIT_SDK_3.4/eclipse/configuration/org.eclipse.osgi/bundles/751/1/.cp/;/D:/HCIT_SDK_3.4/eclipse/configuration/org.eclipse.osgi/bundles/752/1/.cp/, user.name=pengzy, java.vm.specification.version=1.0, java.home=C:\Program Files\Java\jdk1.6.0_20\jre, sun.arch.data.model=32, user.language=zh, java.specification.vendor=Sun Microsystems Inc., awt.toolkit=sun.awt.windows.WToolkit, java.vm.info=mixed mode, sharing, java.version=1.6.0_20, java.ext.dirs=C:\Program Files\Java\jdk1.6.0_20\jre\lib\ext;C:\Windows\Sun\Java\lib\ext, sun.boot.class.path=C:\Program Files\Java\jdk1.6.0_20\jre\lib\resources.jar;C:\Program Files\Java\jdk1.6.0_20\jre\lib\rt.jar;C:\Program Files\Java\jdk1.6.0_20\jre\lib\sunrsasign.jar;C:\Program Files\Java\jdk1.6.0_20\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.6.0_20\jre\lib\jce.jar;C:\Program Files\Java\jdk1.6.0_20\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.6.0_20\jre\classes, java.vendor=Sun Microsystems Inc., file.separator=\, java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi, sun.io.unicode.encoding=UnicodeLittle, sun.cpu.endian=little, sun.desktop=windows, sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86}
分享到:
评论

相关推荐

    jdk1.6.0_45下载jdk-6u45-windows-x64

    附带的`jdk1.6.txt`文件可能包含了关于这个版本的详细信息,比如发行日期、已知问题、修复的Bug列表以及使用指南等。开发者应该仔细阅读这些文档,以便更好地理解和使用JDK 1.6.0_45。 总的来说,JDK 1.6.0_45对于...

    jdk1.6.0_17

    总结来说,JDK 1.6.0_17是Java开发历史上的一个重要里程碑,它为当时的开发者提供了强大的工具集和稳定的运行环境。然而,随着技术的不断进步,更现代的JDK版本如JDK 8、11或17等已经成为主流,它们带来了更多的特性...

    jdk1.6.0_45

    "jdk1.6.0_45"是Oracle公司发布的一个特定版本,该版本属于Java SE(标准版)平台的1.6更新序列中的第45个版本。这个版本的JDK是在Java技术发展历史中一个重要的里程碑,它在功能、性能和安全性上都有所改进。 1. *...

    jdk1.6.0_43.zip

    JDK1.6.0_43是Oracle公司发布的一个重要版本,它属于Java SE(标准版)平台,主要用于桌面应用开发。这个版本的JDK在2013年发布,虽然现在已经比较老旧,但在一些遗留系统或对Java版本有特定需求的项目中仍然被广泛...

    免安装 jdk1.6.0_45

    jdk1.6.0_45"指的是这个版本的JDK是一个便携式版本,无需经过传统意义上的安装过程,用户只需解压缩文件后即可直接使用,这在某些情况下非常方便,比如在没有管理员权限或者希望快速在不同系统间切换开发环境时。...

    jdk1.6.0_22rar

    JDK1.6.0_22是Oracle公司发布的一个较早版本,发布于2011年,尽管现在已经有了更新的版本,但有些开发者出于兼容性或特定项目需求,仍然选择使用这个版本。 这个版本的JDK包含以下几个关键组件: 1. **Java编译器...

    jdk1.6.0_35.rar

    由于JDK 1.6.0_35是一个补丁版本,它可能包含了针对之前版本的安全修复、性能优化和bug修正。对于那些需要在旧环境中运行的应用来说,这个版本是必不可少的。然而,需要注意的是,随着时间的推移,旧版本的JDK不再...

    java jdk1.6.0_10.rar 绿色压缩包

    Java JDK 1.6.0_10 是Oracle公司发布的一个早期版本的Java开发工具包,主要用于Java程序的开发和运行。这个版本是绿色版,意味着它不需要安装,可以直接解压后在系统中使用,方便快捷,尤其适用于那些不希望在计算机...

    jdk1.6.0_31_64

    JDK1.6.0_31_64是Oracle公司发布的一个64位版本的Java开发工具,该版本在Java SE 6的生命周期内进行了一次重要的更新和维护。"jdk1.6.0_31_64.zip" 是这个工具包的压缩文件,包含了运行和开发Java应用所需的所有组件...

    jdk1.6.0_35

    `jdk1.6.0_35`是Oracle公司发布的一个特定版本,这个版本是在Java 6生命周期内的一次更新,主要提供了性能优化、安全性增强和bug修复。 **Java 6(也称为Java SE 6)简介:** Java 6是Java平台标准版的第六个主要...

    jdk1.6.0_38下载

    JDK 1.6.0_38是Java 6的一个更新版本,发布于2013年,为开发者提供了稳定性和安全性方面的改进。 **1. JDK的组成部分** - **Java编译器 (javac)**:将源代码编译成字节码,这是运行在Java虚拟机上的二进制形式。 - ...

    jdk_1.6.0_45

    在这个特定的版本——JDK 1.6.0_45,我们关注的是Java平台的标准版(Java SE)的一个早期版本。这个版本在2014年发布,包含了Java编译器、虚拟机(JVM)、类库以及开发者需要的各种工具,使得开发者能够在Windows...

    jdk1.6.0_32.rar

    Java JDK 1.6.0_32 是Oracle公司发布的一个重要的Java开发工具包,它为开发者提供了编译、调试和运行Java应用程序所需的所有组件。这个版本是针对Java Development Kit的1.6更新32,包含了对先前版本的错误修复和...

    jre1.6_45与jdk1.6_45安装文件

    JDK1.6.0_45是Java 6的一个更新版本,其中“45”代表该版本的更新次数,通常包含了一些bug修复、安全更新和性能改进。开发者需要JDK来编写、编译、测试和调试Java程序。 JRE则是运行Java应用程序所必需的环境,它...

    jdk1.6_64位官方下载

    在本案例中,我们讨论的是JDK1.6的64位版本,具体为JDK1.6.0_45,这是一个官方的标准版。 1. **64位版本**:64位版本的JDK针对64位操作系统设计,它可以更好地利用现代计算机的多核处理器和大量内存,提高性能并...

    JDK1.6.0.24-64位

    3. **Java运行时环境(JRE)**:这是运行Java应用程序所必需的基础组件,包括JVM、Java类库和其他支持文件。JDK包含JRE,但JRE本身不包含编译器和其他开发工具。 4. **Java文档生成器(javadoc)**:此工具用于自动...

    Java SE 1.6.0_15 SDK文档(javadoc版本)

    总的来说,Java SE 1.6.0_15 SDK文档对于Java开发者来说是一个宝贵的参考资料,无论是在学习阶段还是实际开发过程中,都可以从中获取详尽的API信息,有助于理解和应用Java的各种功能,提高开发效率。

    jdk1.6.0-41位官方正式版 jdk1.6.0-41-windows

    首先,JDK1.6.0_41是Java 6的一个更新版本,发布于2012年。这个版本修复了许多已知的bug,提高了性能,并引入了一些新特性。例如,它增强了垃圾收集器的效率,提升了多线程编程的稳定性和安全性。此外,JDK1.6还支持...

Global site tag (gtag.js) - Google Analytics