Java反射

Java反射

在这里插入图片描述

获取类对应的字节码的对象

//通过读取配置文件
Class aClass1 = Class.forName("类的全路径");
System.out.println(aClass1);
//类名.class   应用场景:参数传递
Class aClass2 = Dog.class;
System.out.println(aClass2);
//对象.getClass()   应用场景:有对象实例
Dog dog1 = new Dog();
Class aClass3 = dog1.getClass();
System.out.println(aClass3);
//类加载器
ClassLoader classLoader = dog1.getClass().getClassLoader();
Class aClass4 = classLoader.loadClass("com.wang.test2.Dog");
System.out.println(aClass4);
//hashCode相等  在堆中一个用户只有一个Class对象
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
System.out.println(aClass4.hashCode());

常用方法

//获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名

//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)

//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)

//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)

//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"韦小宝");//执行有参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法

//反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null

//反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法

synchronized关键字

Synchronized锁存储位置

Synchronized用的锁是存在java的对象头里面的。一个对象在new出来之后再内存中主要分为4个部分:

在这里插入图片描述

Mark Word:存储了对象的hashCode、GC信息、锁信息三部分。这部分占8字节。

Class Pointer:存储了指向类对象信息的指针。在64位JVM上有一个压缩指针选项-ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节。默认是开启的。

实例数据(instance data):记录了对象里面的变量数据。引用类型:-XX:+UseCompressedOops 为4字节 不开启为8字节 Oops Ordinary Object Pointers

Padding:作为对齐使用,对象在64位服务版本中,规定对象内存必须要能被8字节整除,如果不能整除,那么久靠对齐来不。举个例子:new出了一个对象,内存只占用18字节,但是规定要能被8整除,所以padding=6
Mark Word存储结构如下:
32位虚拟机下:

在这里插入图片描述

64位虚拟机下:

在这里插入图片描述

CAS : compare and swap (比较和交换)。

当我们需要对内存中的数据进行修改操作时,为了避免多线程并发修改的情况,我们在对他进行修改操作前,先读取他原来的值E,然后进行计算得出新的的值V,在修改前去比较当前内存中的值N是否和我之前读到的E相同,如果相同,认为其他线程没有修改过内存中的值,如果不同,说明被其他线程修改了,这时,要继续循环去获取最新的值E,再进行计算和比较,直到我们预期的值和当前内存中的值相等时,再对数据执行修改操作。

CAS具体流程如下下图:
在这里插入图片描述

ABA问题解决方案:加上版本号(基础类型简单值不需要版本号)

Synchronized锁的升级过程

Java SE 1.6 为了减少获得锁和释放锁带来的性能消耗,引入了 “偏向锁” 和 “轻量级锁”:锁一共有 4 种状态,级别从低到高依次是:无锁状态偏向锁状态轻量级锁状态重量级锁状态锁可以升级但不能降级线程通过CAS机制获取锁( 替换对象头中的线程id)

偏向锁:大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。当一个线程访问同步块并获取锁时,会在对象头和栈帧中记录存储锁偏向的线程ID,以后该线程在进入同步块时先判断对象头的Mark Word里是否存储着指向当前线程的偏向锁,如果存在就直接获取锁。

偏向锁获取流程如下图:
在这里插入图片描述

轻量级锁:当其他线程尝试竞争偏向锁时,锁升级为轻量级锁。线程在执行同步块之前,JVM会先在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头中的MarkWord替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,标识其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

重量级锁:锁在原地循环等待的时候,是会消耗CPU资源的。所以自旋必须要有一定的条件控制,否则如果一个线程执行同步代码块的时间很长,那么等待锁的线程会不断的循环反而会消耗CPU资源。默认情况下锁自旋的次数是10 次,可以使用-XX:PreBlockSpin参数来设置自旋锁等待的次数。10次后如果还没获取锁,则升级为重量级锁。

几种锁状态优缺点对比

在这里插入图片描述

volatile关键字

1.线程可见性

package com.mashibing.testvolatile;

public class T01_ThreadVisibility {
    private static volatile boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(()-> {
            while (flag) {
                //do sth
            }
            System.out.println("end");
        }, "server").start();


        Thread.sleep(1000);

        flag = false;
    }
}

2.防止指令重排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值