0
点赞
收藏
分享

微信扫一扫

数字社交的新典范:解析Facebook的成功密码

认真的老去 2天前 阅读 0

CountDownLatchCyclicBarrier

JUC 并发编程_juc并发编程-CSDN博客

 java 类加载机制?如何实现自定义类加载器?findClass 与 loadClass 的区别?

在Java中,自定义类加载器通常是通过继承java.lang.ClassLoader类并重写其findClass方法来实现的,该方法首先调用从文件系统获取类的字节码,然后使用defineClass方法将这些字节码转换成Class对象实例。需要注意的是,loadClass方法已经被ClassLoader实现过了,它会首先尝试调用父类加载器来加载类,只有在父类加载器加载失败的情况下,才会调用findClass方法。

自定义类加载器:

public class MyClassLoader extends ClassLoader{


    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String path="E:\\demo\\"+name+".class";
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            Files.copy(Paths.get(path),byteArrayOutputStream);

            //得到class文件的字节数组
            byte[] bytes = byteArrayOutputStream.toByteArray();
            // 调用defineClass将字节码转化为Class实例
            return defineClass(name,bytes,0,bytes.length);

        }catch (IOException e){
            e.printStackTrace();
            throw new ClassNotFoundException("类文件未找到",e);
        }
    }
}

注意:在Java中,一个类的身份不仅由其完整名字(包括包名)决定,还由加载它的类加载器决定。换句话说,即使两个类来自同一份字节码文件,如果它们被不同的类加载器实例加载,那么在JVM中,它们也会被视为不同的类。

  MyClassLoader classLoader=new MyClassLoader();
        Class<?> aClass = classLoader.loadClass("Demo");
        Class<?> aClass1 = classLoader.loadClass("Demo");
        System.out.println(aClass==aClass1); //true

        MyClassLoader myClassLoader=new MyClassLoader();
        Class<?> aClass2 = myClassLoader.loadClass("Demo");
        System.out.println(aClass==aClass2); //false

loadClass方法

loadClass是类加载的入口点。当你的代码尝试加载一个类时(通过Class.forName、反射等方式),最终都会调用到类加载器的loadClass方法。loadClass方法的主要职责是按照双亲委派模型来加载类:

  1. 检查类是否已加载:首先检查这个类是否已经被加载过了。如果已加载,就直接返回该类的Class对象。这保证了每个类在JVM内部只有一个Class实例。
  2. 双亲委派:如果类还没有被加载,loadClass会先委托给父类加载器尝试加载这个类。只有当父类加载器无法加载该类时(因为它不在父类加载器的搜索范围内),才会尝试自己加载。
  3. 调用findClass方法:如果所有父类加载器都无法加载这个类,loadClass方法最终会调用类加载器自己的findClass方法来加载这个类。

findClass方法

findClass方法是ClassLoader的一个受保护方法,它在类加载器的类加载机制中起到实际加载类的作用。当一个类加载器的父类加载器都无法加载某个类时,这个类加载器的findClass方法就会被调用。

栈会不会溢出?栈溢出一般抛什么异常?jvm 在哪里设置栈的大小?设置的参数是什
么?

如果线程请求分配的栈容量超过java虚拟机栈允许的最大容量的时候,java虚拟
机将抛出一个StackOverFlowError异常,可以通过命令行参数设置栈的大小,java -Xss512k Application,-Xms设置堆的初始大小,-Xmx设置堆的最大大小。

java 线程池?线程池构造函数的几个参数含义?keepAliveTime 解释一下?

 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        3,  // 核心线程数量
        6,              //最大线程数
        60,             //空闲临时线程最大存活时间(数值)
        TimeUnit.SECONDS,//空闲临时线程最大存活时间(单位)
        new ArrayBlockingQueue<>(3),//任务队列,也就是一个堵塞队列,也可以使用LinkedBlockingQueue这个阻塞队列
        Executors.defaultThreadFactory(),//用线程池工具类Executors创建线程的工厂
        new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略中其中一个,丢弃任务并抛出RejectedExecutionException
    );

线程等待和唤醒的实现方式

  • Object 类下的 wait()、notify() 和 notifyAll() 方法;
  • Condition 类下的 await()、signal() 和 signalAll() 方法;
  • LockSupport 类下的 park() 和 unpark() 方法。

LockSupport 类的方法说明:

  1. LockSupport.park():休眠当前线程。
  2. LockSupport.unpark(线程对象):唤醒某一个指定的线程。

线程池拒绝策略

判断线程池中的任务已经全部执行完,等所有任务都执行完之后,进行数据的组装和返回

1. 使用 CountDownLatch 或 CyclicBarrier 等待所有线程都执行完之后,再执行后续流程。

2. CompletableFuture

ThreadPoolExecutor pool = new ThreadPoolExecutor(3, 5, 2, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3));
        CompletableFuture<Void> a = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
        }, pool);
        CompletableFuture<Void> b = CompletableFuture.runAsync(() -> {
            System.out.println(Thread.currentThread().getName());
        }, pool);
        //等待两个线程执行完毕
        CompletableFuture.allOf(a,b).get();

ConcurrentHashMap为什么不允许插入Null

 volatile有序性

死锁

解决方案:

  1. 按照顺序加锁:尝试让所有线程按照同一顺序获取锁,从而避免死锁。
  2. 设置获取锁的超时时间:尝试获取锁的线程在规定时间内没有获取到锁,就放弃获取锁,避免因为长时间等待锁而引起的死锁。

死锁排查工具:jconsole 和 JVisualVM:这些是 Java 自带的监视工具,可以用于监视线程、内存、CPU 使用率等信息,从而帮助排查死锁问题。

举报

相关推荐

0 条评论