JDK JRE JVM关系?
JDK–Java Development Kit是针对java开发员的产品,是整个java的核心,包括java运行环境JRE、java工具和java基础类库。
JRE–Java Runtime Environment是针对JAVA的运行时环境,包含JVM和java核心类库。
JVM–Java Virtual Machine,java虚拟机的缩写,是整个java实现跨平台的最核心的部分,能够运行java写的软件程序。
JDK > JRE >JVM
JDK = JRE+java工具+java基础类库
JRE = JVM + java核心类库
JVM运行时数据区
方法区(Methods Area)、堆(Heap)、虚拟机栈(VM Stack)、本地方法栈(Native Methods Stack)、程序计数器(Program Count Register)。
方法区:类信息、常量、静态变量、即时编译器编译后的代码。
堆:对象实例和数组。
虚拟机栈:局部变量表、操作数栈、动态链接、方法出口。
本地方法栈:Native方法。
程序计数器:虚拟机字节码指令的地址或undefined。
1.一般来讲局部变量存在栈中,方法执行完毕后内存就会被释放。
2.对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放。
3.每个堆内存中的数据都有地址值
3.对象中的属性都是有默认值的
构造代码块是最优先的,局部代码块顺序执行。
单例设计模式
饿汉式
目的:控制外界创建对象的个数只能创建1个对象,保证一个类只有一个实例。要提供一个访问该类对象实例的全局访问点。
开发步骤:
1、 私有化构造方法
2、 在类的内部创建好对象
3、 对外界提供一个公共的get(),返回一个已经准备好的对象
package cn.tedu.single;
//测试单例设计模式
public class Test8_Single {
public static void main(String[] args) {
Single s = Single.get();
Single s1 = Single.get();
//get()多少次,内存中使用的都是同一个对象
System.out.println(s);//cn.tedu.single.Single@15db9742
System.out.println(s1);//cn.tedu.single.Single@15db9742
ThreadTestSingleton1();
}
public static void ThreadTestSingleton1() {
Thread one = new Thread(new ThreadSingle1());
Thread two = new Thread(new ThreadSingle1());
one.start();
two.start();
}
}
class Single{
// 1、私有化构造方法,不让外界直接new
private Single() {}
// 2、在类的内部,创建好对象
//static :静态只能调用静态
static private Single s = new Single();
// 3、对外界提供一个公共的get(),返回一个已经准备好的对象
//static是为了外界不通过对象访问而是通过类名直接方法
static public Single get(){
//注意:静态只能调用静态
return s;
}
}
懒汉式
class Single{
// 1、私有化构造方法,不让外界直接new
private Single() {}
// 2、在类的内部,创建好对象
//static :静态只能调用静态
static private Single s = null;
// 3、对外界提供一个公共的get(),返回一个已经准备好的对象
//static是为了外界不通过对象访问而是通过类名直接方法
static public Single get(){
//注意:静态只能调用静态
if(s==null){
s = new Single();//会有安全问题
}
return s;
}
}
class ThreadSingle1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(20);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();;
}
System.out.println(Thread.currentThread().getName()+"懒汉式"+Single1.get());
}
}
class ThreadSingle implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(20);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();;
}
System.out.println(Thread.currentThread().getName()+"饥汉式"+Single.get());
}
}
总结两点:
饿汉式这种方式称之为预先加载类对象;
懒汉式这种方式称之为延迟加载类对象。
分析懒汉式代码
将代码上锁后,每次执行都要检测锁,效率不高,所以我们只有在对象创建时才上锁,保证对象的唯一,一旦对象都存在了,以后操作就不需要锁了。所以代码如下:
class Single1{
static private Single1 s = null;
static public Single1 get() {
if(s==null) {
//若对象不存在上锁则分配新对象
synchronized (Single1.class) {//使用该类对应的字节码文件对象上锁
//synchronized用于代码块的时候需要一个锁对象,用于实例方法上使用的this对象
//当应用于类方法的时候(static)我们可以使用该类的字节码文件对象,this这个时候不存在
if(s==null)
s = new Single1();
}
}
return s;
}
}
总计
饿汉式:
对象预先加载,线程是安全的,在类创建好的同时对象生成,调用获得对象实例的方法反应速度快,代码简练。
懒汉式:
对象延迟加载,效率高,只有在使用的时候才实例化对象,但若设计不当线程会不安全,代码相对于饿汉式复杂,第一次加载类对象的时候反应不快。