系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
提示:这里可以添加本文要记录的大概内容:
记录Java非web相关的知识点
提示:以下是本篇文章正文内容,下面案例可供参考
类
内部类
静态内部类和内部类的区别
主要是访问外部成员的区别
public class OuterClass {
private String outerField; // 非静态成员
private static String staticOuterField; // 静态成员
public InnerClass innerClass = new InnerClass();
public StaticInterClass staticInterClass = new StaticInterClass();
public class InnerClass {
public void printFields() {
System.out.println(outerField); // 可访问非静态成员
System.out.println(staticOuterField); // 可访问静态成员
}
}
public static class StaticInterClass {
public void printFields() {
System.out.println(outerField); // 报错,不可访问非静态成员
System.out.println(staticOuterField); // 可访问静态成员
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
// 类的访问有区别
OuterClass.StaticInterClass staticInterClass = new OuterClass.StaticInterClass(); // 静态内部类可以直接通过类来访问
OuterClass.InnerClass in = new OuterClass.InnerClass(); // 报错,内部类不能通过类去访问
// 类实例的访问是一样的
outerClass.innerClass.printFields();
outerClass.staticInterClass.printFields();
}
}
作者:铿然架构
链接:https://juejin.cn/post/6844904114506170382
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
集合类
concurrent
LinkedBlockingQueue
多线程
ThreadPoolExecutor
参考文献:https://juejin.cn/post/6901317365561032712
构造方法:
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
)
核心线程:
为了避免频繁地创建和销毁线程,线程池需要缓存一定数量的线程,即使其处于空闲状态也不会进行回收,这类线程我们就称之为核心线程,相应的线程数量就称之为核心线程池大小(corePoolSize)。大于 corePoolSize 而小于等于 maximumPoolSize 的那一部分线程,就称之为非核心线程。
当核心线程都已经被创建了时,此后外部提交的任务就被缓存到任务队列中,当任务队列满了后才创建非核心线程来循环处理任务
超过maximumPoolSize 时:
若使用无界队列,就可能使得当系统发生异常时程序还是看起来运转正常,从而降低了系统健壮性。因为有界队列之所以会满,可能是由于发生线程池死锁或者依赖的某个基础服务失效导致的,从而令线程池中的任务一直迟迟得不到解决。
现实需求是多样化的,在实现线程池时就需要留有交由外部自定义处理策略的余地。即定义RejectedExecutionHandler 。
线程状态
实际上 ThreadPoolExecutor 就是通过将一个 32 位的 int 类型变量分割为两段,高 3 位用来表示线程池的当前生命周期状态,低 29 位就拿来表示线程池的当前线程数量,从而做到用一个变量值来维护两份数据,这个变量值就是 ctl。这种用一个变量去存储两个值的做法,可以避免在做相关决策时出现不一致的情况,且不必为了维护两者的一致而使用锁
excute()执行流程
Worker
Worker 内部包含了一个 Thread 对象
Worker 继承于 AbstractQueuedSynchronizer,意味着 Worker 就相当于一个锁。之没有使用 synchronized 或者 ReentrantLock,是因为它们都是可重入锁,Worker 继承于 AQS 为的就是自定义实现不可重入的特性来辅助判断线程是否处于执行任务的状态:在开始执行任务前进行加锁,在任务执行结束后解锁,以便在后续通过判断 Worker 是否处于锁定状态来得知其是否处于执行阶段
动态代理
为什么类可以动态的生成?
这就涉及到Java虚拟机的类加载机制了
JDK动态代理使用实例
- 编写xxInvocationHandler继承java.lang.reflect.InvocationHandler
- Proxy.newProxyInstance(某classLoader, 目标类或目标类的接口数组, xxInvocationHandler);
- 动态得到目标类的接口数组的新实现类,或目标类的子类?
参考链接添加链接描述
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicLong;
/**
* 线程池拒绝策略代理执行器
*
* @公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
*/
@Slf4j
@AllArgsConstructor
public class RejectedProxyInvocationHandler implements InvocationHandler {
/**
* Target object
*/
private final Object target;
/**
* Reject count
*/
private final AtomicLong rejectCount;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
rejectCount.incrementAndGet();
try {
log.error("线程池执行拒绝策略, 此处模拟报警...");
return method.invoke(target, args);
} catch (InvocationTargetException ex) {
throw ex.getCause();
}
}
}
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.opengoofy.index12306.framework.starter.common.toolkit.ThreadUtil;
import java.lang.reflect.Proxy;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* 拒绝策略代理工具类
*
* @公众号:马丁玩编程,回复:加群,添加马哥微信(备注:12306)获取项目资料
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class RejectedProxyUtil {
/**
* 创建拒绝策略代理类
*
* @param rejectedExecutionHandler 真正的线程池拒绝策略执行器
* @param rejectedNum 拒绝策略执行统计器
* @return 代理拒绝策略
*/
public static RejectedExecutionHandler createProxy(RejectedExecutionHandler rejectedExecutionHandler, AtomicLong rejectedNum) {
// 动态代理模式: 增强线程池拒绝策略,比如:拒绝任务报警或加入延迟队列重复放入等逻辑
return (RejectedExecutionHandler) Proxy
.newProxyInstance(
rejectedExecutionHandler.getClass().getClassLoader(),
new Class[]{RejectedExecutionHandler.class},
new RejectedProxyInvocationHandler(rejectedExecutionHandler, rejectedNum));
}
/**
* 测试线程池拒绝策略动态代理程序
*/
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(1, 3, 1024, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1));
ThreadPoolExecutor.AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();
AtomicLong rejectedNum = new AtomicLong();
RejectedExecutionHandler proxyRejectedExecutionHandler = RejectedProxyUtil.createProxy(abortPolicy, rejectedNum);
threadPoolExecutor.setRejectedExecutionHandler(proxyRejectedExecutionHandler);
for (int i = 0; i < 5; i++) {
try {
threadPoolExecutor.execute(() -> ThreadUtil.sleep(100000L));
} catch (Exception ignored) {
ignored.printStackTrace();
}
}
System.out.println("================ 线程池拒绝策略执行次数: " + rejectedNum.get());
}
}