b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Java反射工作机制(3)

电脑杂谈  发布时间:2019-07-08 15:14:58  来源:网络整理

spring单例在高并发下可能出现的错误. spring单例在高并发下可能出现的错误: 首先,只有当注入的对象是无状态的幂等的才可以保证执行前后不被修改,否则执行一次之后单例对象就会发生改变,在下次执行有肯能造成结果不一样,当在高并发的情况下就会出现,这个线程刚使用单例对象进行属性设置,还未使用的情况下,另一个进程已经将单利对象的数据进行修改属性完成,则远来线程获取到的单例就是一个脏对象不可使用.。ps:上面代码中还有两个地方要注意:一个地方是$exampledo.getitemlist()代码被解析成_i.exampledo).getitemlist()方法调用(第一次编译时是通过反射调用,多次编译后通过方法调用)java反射机制,也就是将velocity的动态反射调用变成了java的原生方法调用。tryenter重载方法 作用:该方法的意思是,尝试着获取资源的互斥锁,在指定的时间内(不指定就默认无限大,阻塞)获取了就返回true执行下面的临界区代码(这个方法调用后和释放锁之间的代码都是临界区代码),否则,返回false,执行下面的代码(没有获取到锁,下面的代码不是临界区代码)。

 @CallerSensitive
    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

然后,看下获取MethodAccessor方法,首先也是从缓存中获取,如果获取不到就调用reflectionFactory.newMethodAccessor方法获取一个并设置缓存

private MethodAccessor acquireMethodAccessor() {
        MethodAccessor tmp = null;
        if (root != null) tmp = root.getMethodAccessor();
        if (tmp != null) {
            methodAccessor = tmp;
        } else {
            tmp = reflectionFactory.newMethodAccessor(this);
            setMethodAccessor(tmp);
        }
        return tmp;
    }

java反射机制_java 反射内存_java 反射原理

然后,具体看下newMethodAccesor方法,该方法可以使用inflation机制创建accessor,初始的时候noInfalation值为false,所以开始的时候会调用NativeMethodAccessorImpl的方法invoke。

private static boolean noInflation        = false;
private static int     inflationThreshold = 15;
 public MethodAccessor newMethodAccessor(Method method) {
        checkInitted();
        if (noInflation) {
            return new MethodAccessorGenerator().
                generateMethod(method.getDeclaringClass(),
                               method.getName(),
                               method.getParameterTypes(),
                               method.getReturnType(),
                               method.getExceptionTypes(),
                               method.getModifiers());
        } else {
            NativeMethodAccessorImpl acc =
                new NativeMethodAccessorImpl(method);
            DelegatingMethodAccessorImpl res =
                new DelegatingMethodAccessorImpl(acc);
            acc.setParent(res);
            return res;
        }
    }

再次,看下NativeMethodAccessorImpl的实现,这里的++numInvocations就是统计次数的,有源码可以看出,前15次会调用native的invoke0方法,这种方法初始化比较快,但性能不够好。而过了15次之后都是底层调用asm给Method生成字节码然后加载到内存形成对象进行调用的,这种方式初始化较慢,但性能较好。

class NativeMethodAccessorImpl extends MethodAccessorImpl {
    private Method method;
    private DelegatingMethodAccessorImpl parent;
    private int numInvocations;
    NativeMethodAccessorImpl(Method method) {
        this.method = method;
    }    
    public Object invoke(Object obj, Object[] args)
        throws IllegalArgumentException, InvocationTargetException
    {
        if (++numInvocations > ReflectionFactory.inflationThreshold()) {
            MethodAccessorImpl acc = (MethodAccessorImpl)
                new MethodAccessorGenerator().
                    generateMethod(method.getDeclaringClass(),
                                   method.getName(),
                                   method.getParameterTypes(),
                                   method.getReturnType(),
                                   method.getExceptionTypes(),
                                   method.getModifiers());
            parent.setDelegate(acc);
        }
        return invoke0(method, obj, args);
    }
    void setParent(DelegatingMethodAccessorImpl parent) {
        this.parent = parent;
    }
    private static native Object invoke0(Method m, Object obj, Object[] args);
}

最后,来看下asm生成字节码方法的实现,这个方法的最后返回了一个MagicAccesorImpl(开始是没有实现的空类),其中的AccessController.doPrivileged(new PrivilegeAction)相当于执行一个任务,该任务调用ClassDefiner的defineClass方法,该方法内部同样也是执行任务,但内部的方法每次执行的时候都会返回一个类加DelegatingClassLoader类加载器,然后把类的一些字节码信息连同这个类加载器一起交给unsafe让他去把字节码通过类加载器加载到内存里面来以MagicAccessorImpl的类形式存在与内存中。

return (MagicAccessorImpl) AccessController.doPrivileged(new PrivilegedAction() {
                public MagicAccessorImpl run() {
                    try {
                        return (MagicAccessorImpl) ClassDefiner
                                .defineClass(arg12, arg16, 0, arg16.length, arg0.getClassLoader()).newInstance();
                    } catch (IllegalAccessException | InstantiationException arg1) {
                        throw new InternalError(arg1);
                    }
                }
            });
class MagicAccessorImpl {
}
class ClassDefiner {
    static final Unsafe unsafe = Unsafe.getUnsafe();
    static Class<?> defineClass(String arg, byte[] arg0, int arg1, int arg2, final ClassLoader arg3) {
        ClassLoader arg4 = (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
            public ClassLoader run() {
                return new DelegatingClassLoader(arg3);
            }
        });
        return unsafe.defineClass(arg, arg0, arg1, arg2, arg4, (ProtectionDomain) null);
    }
}

我们需要实现一个defaultactioninvoker以默认的方式进行方法的调用,也就是找到方法的一些ifilter按照一定的顺序执行他们,最后使用反射进行方法的调用得到上面说的iactionresult并执行它的execute()方法。调用线程类的start()方法使该线程开始执行。当a线程调用anyobject对象加入synchronized关健字的x方法时,a线程就获得了x方法所在对象的锁,所以其他线程必须等a线程执行完毕才可以调用x方法,而b线程如果调用声明了synchronized关键字的非x方法时,必须等a线程将x方法执行完,也就是释放对象锁后才可以调用。

Method method = clazz.getDeclaredMethod("methodReflected");
method.invoke(target);
@CallerSensitive
    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

的执行结果是:___52____ 答:date是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20。方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。答:sleep()方法(休眠)是线程类(thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(cpu)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态java反射机制,请参考第66题中的线程状态转换图)。

12062369-8e863469bc53fefb.png

image.png

12062369-3d2baa697dabeab3.png

image.png


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-111385-3.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    • 周孝闵帝宇文觉
      周孝闵帝宇文觉

      为了他的电商事业

    热点图片
    拼命载入中...