直接内存
1. 不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域
2. 直接内存是在Java堆外、直接向系统申请的内存区间
3. 来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存
4. 通常,访问直接内存的速度会优于Java堆,即读写性能高
5. 处于性能考虑,读写操作频繁的场合会考虑使用直接内存
6. Java的NIO库允许Java程序使用直接内存,用于数据缓冲区
7. 由于直接内存在Java堆外,因此它的大小不会直接受限于-Xmx指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。
8. 直接内存的大小可以通过MaxDirectMemorySize设置,如果不指定,则默认于堆的最大值-Xmx参数值一致
缺点:
分配回收成本较高
不受JVM内存回收管理
public class BufferTest {private static final int BUFFER=1024*1024*1024;//1GBpublic static void main(String[] args) {
// 直接分配内存空间ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);System.out.println("直接内存分配完毕,请求指示!");Scanner scanner=new Scanner(System.in);scanner.next();System.out.println("直接内存开始释放");byteBuffer =null;System.gc();scanner.next();}
}
死锁
public class TestDeadLock implements Runnable { public int flag = 1; static Object o1 = new Object(), o2 = new Object();public void run() { System.out.println("flag=" + flag); if (flag == 1) { synchronized (o1) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o2) { System.out.println("1"); } } } if (flag == 0) { synchronized (o2) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o1) { System.out.println("0"); } } }
}
当flag为1时,线程首选获取o1锁,休眠500毫秒,然后尝试获取o2的锁,如果成功过,则打印"1".
当flag为2时,线程首选获取o2锁,休眠500毫秒,然后尝试获取o1的锁,如果成功过,则打印"0".
由于td1和flag为1,它首先获取了o1的锁,并休眠500毫秒。在td1休眠期间,td2开始执行并获取了o2的锁。当td1醒来兵尝试获取o2的锁时,它会被阻塞,因为o2的锁已经被td2持有,同样地,当td2醒来兵尝试获取o1的锁时,因为o1的锁已经被td1持有,这样,两个线程都陷入了等待状态,形成了死锁
为了避免死锁,可以采取以下策略:
方法句柄
静态方法句柄
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;public class MethodHandleExample {public static void staticMethod(){System.out.println("static method called");}public static void main(String[] args) throws Throwable {
// 获取当前类的查找器MethodHandles.Lookup lookup=MethodHandles.lookup();
// 创建静态方法句柄MethodHandle methodHandle=lookup.findStatic(MethodHandleExample.class,"staticMethod", MethodType.methodType(void.class));
// 调用方法句柄methodHandle.invoke(); // static method called}
}
实例方法句柄
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; public class MethodHandleExample { public void instanceMethod() { System.out.println("Instance method called"); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException { // 创建类的实例 MethodHandleExample example = new MethodHandleExample(); // 获取当前类的查找器 MethodHandles.Lookup lookup = MethodHandles.lookup(); // 创建实例方法句柄 MethodHandle methodHandle = lookup.findVirtual(MethodHandleExample.class, "instanceMethod", MethodType.methodType(void.class)); // 绑定实例并调用方法句柄 methodHandle.bindTo(example).invoke(); }
}
构造函数句柄
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; public class MethodHandleExample { public MethodHandleExample() { System.out.println("Constructor called"); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException { // 获取当前类的查找器 MethodHandles.Lookup lookup = MethodHandles.lookup(); // 创建构造函数句柄 MethodHandle constructorHandle = lookup.findConstructor(MethodHandleExample.class, MethodType.methodType(void.class)); // 调用构造函数句柄创建实例 MethodHandleExample example = (MethodHandleExample) constructorHandle.invoke(); }
}
方法句柄优势
方法句柄比传统的Java反射API更快,因为他们直接利用了JVM内部机制
方法句柄可以绑定到各种类型的方法上,包括私有方法和构造函数
方法句柄的访问控制更加细粒度,可以在运行时动态调整权限
public class Test {class GrandFather{void thinking(){System.out.println("GrandFather ");}}class Father extends GrandFather{void thinking(){System.out.println("Father");}}class Son extends Father{void thinking(){try {MethodType mt=MethodType.methodType(void.class);// 获取当前类的查找器MethodHandles.Lookup lookup=MethodHandles.lookup();
// 创建句柄MethodHandle mh=lookup.findSpecial(GrandFather.class,"thinking",mt,getClass());mh.invoke(this);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (Throwable e) {throw new RuntimeException(e);}}}public static void main(String[] args) {(new Test().new Son()).thinking();}
}
public class Test {class GrandFather{void thinking(){System.out.println("GrandFather ");}}class Father extends GrandFather{void thinking(){System.out.println("Father");}}class Son extends Father{void thinking(){try {MethodType mt=MethodType.methodType(void.class);// 反射,绕过保护机制Field lookupImpl =MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");lookupImpl.setAccessible(true);
// 获取当前类的查找器
// MethodHandles.Lookup lookup=MethodHandles.lookup();
// 创建句柄MethodHandle mh=((MethodHandles.Lookup)lookupImpl.get(null)).findSpecial(GrandFather.class,"thinking",mt,GrandFather.class);mh.invoke(this); //GrandFather} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (Throwable e) {throw new RuntimeException(e);}}}public static void main(String[] args) {(new Test().new Son()).thinking();}
}