邯郸网站seo,建一个手机网站需要多少钱,php企业网站建设,杭州互联网企业排名CountDownLatch和CyclicBarrier
JUC 并发编程_juc并发编程-CSDN博客 java 类加载机制#xff1f;如何实现自定义类加载器#xff1f;findClass 与 loadClass 的区别#xff1f;
在Java中#xff0c;自定义类加载器通常是通过继承java.lang.ClassLoader类并重写其findClas…CountDownLatch和CyclicBarrier
JUC 并发编程_juc并发编程-CSDN博客 java 类加载机制如何实现自定义类加载器findClass 与 loadClass 的区别
在Java中自定义类加载器通常是通过继承java.lang.ClassLoader类并重写其findClass方法来实现的该方法首先调用从文件系统获取类的字节码然后使用defineClass方法将这些字节码转换成Class对象实例。需要注意的是loadClass方法已经被ClassLoader实现过了它会首先尝试调用父类加载器来加载类只有在父类加载器加载失败的情况下才会调用findClass方法。
自定义类加载器
public class MyClassLoader extends ClassLoader{Overrideprotected Class? findClass(String name) throws ClassNotFoundException {String pathE:\\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 classLoadernew MyClassLoader();Class? aClass classLoader.loadClass(Demo);Class? aClass1 classLoader.loadClass(Demo);System.out.println(aClassaClass1); //trueMyClassLoader myClassLoadernew MyClassLoader();Class? aClass2 myClassLoader.loadClass(Demo);System.out.println(aClassaClass2); //false
loadClass方法
loadClass是类加载的入口点。当你的代码尝试加载一个类时通过Class.forName、反射等方式最终都会调用到类加载器的loadClass方法。loadClass方法的主要职责是按照双亲委派模型来加载类
检查类是否已加载首先检查这个类是否已经被加载过了。如果已加载就直接返回该类的Class对象。这保证了每个类在JVM内部只有一个Class实例。双亲委派如果类还没有被加载loadClass会先委托给父类加载器尝试加载这个类。只有当父类加载器无法加载该类时因为它不在父类加载器的搜索范围内才会尝试自己加载。调用findClass方法如果所有父类加载器都无法加载这个类loadClass方法最终会调用类加载器自己的findClass方法来加载这个类。
findClass方法
findClass方法是ClassLoader的一个受保护方法它在类加载器的类加载机制中起到实际加载类的作用。当一个类加载器的父类加载器都无法加载某个类时这个类加载器的findClass方法就会被调用。
栈会不会溢出栈溢出一般抛什么异常jvm 在哪里设置栈的大小设置的参数是什 么
如果线程请求分配的栈容量超过java虚拟机栈允许的最大容量的时候java虚拟 机将抛出一个StackOverFlowError异常可以通过命令行参数设置栈的大小java -Xss512k Application-Xms设置堆的初始大小-Xmx设置堆的最大大小。
JIT 、逃逸分析、锁消除、栈上分配、标量替换 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 类的方法说明
LockSupport.park()休眠当前线程。LockSupport.unpark(线程对象)唤醒某一个指定的线程。
线程池拒绝策略 判断线程池中的任务已经全部执行完等所有任务都执行完之后进行数据的组装和返回
1. 使用 CountDownLatch 或 CyclicBarrier 等待所有线程都执行完之后再执行后续流程。
2. CompletableFuture
ThreadPoolExecutor pool new ThreadPoolExecutor(3, 5, 2, TimeUnit.SECONDS, new ArrayBlockingQueue(3));CompletableFutureVoid a CompletableFuture.runAsync(() - {System.out.println(Thread.currentThread().getName());}, pool);CompletableFutureVoid b CompletableFuture.runAsync(() - {System.out.println(Thread.currentThread().getName());}, pool);//等待两个线程执行完毕CompletableFuture.allOf(a,b).get();
ConcurrentHashMap为什么不允许插入Null volatile有序性 死锁
解决方案
按照顺序加锁尝试让所有线程按照同一顺序获取锁从而避免死锁。设置获取锁的超时时间尝试获取锁的线程在规定时间内没有获取到锁就放弃获取锁避免因为长时间等待锁而引起的死锁。
死锁排查工具jconsole 和 JVisualVM这些是 Java 自带的监视工具可以用于监视线程、内存、CPU 使用率等信息从而帮助排查死锁问题。