Java核心知识点(持续更新中)

本文详细讲解了Java中的线程与线程池概念,包括状态、方法区别、创建方式以及线程池配置。此外,还涵盖了锁机制(轻量级锁、重量级锁、ReentrantLock)、读写锁、CountDownLatch和Semaphore的使用,以及如何避免线程死锁和Java容器(如Collection和Map)的基础知识。
摘要由CSDN通过智能技术生成

线程与线程池

线程

一、线程的状态
在这里插入图片描述
二、 sleep、wait、join、yield 方法的区别

1、sleep 与 wait 方法的区别
(1)sleep 是 Thread 类的静态本地方法;wait 则是 Object 类的本地方法。
(2)sleep 方法不会释放 lock;但是 wait 会释放,而且会加入到等待队列中。
(3)sleep 方法不依赖于同步器 synchronized;但是 wait 方法需要依赖 synchronized关键字。
(4)sleep 不需要被主动唤醒(休眠时间结束后退出阻塞);但是 wait 方法需要(不指定时间时,需要被别人中断)。
(5)sleep 方法一般用于当前线程休眠,或者轮询暂停操作;wait 方法则多用于线程之间的通信(得益于wait会释放锁)。
(6)sleep 会让出 CPU 执行时间且强制上下文切换;而 wait 则不一定,wait 后可能还是有机会重新竞争到锁继续执行。

2、yield 方法
yield 方法执行后线程直接进入就绪态,马上释放CPU的执行权,但是依然保留了CPU的执行资格,所以有可能CPU下次进行线程调度时,还会让这个线程获取到执行权继续执行。

3、join 方法
线程执行 join 方法后会进入阻塞状态。例如在线程B中调用线程A的 join 方法,那么线程B就会进入阻塞队列中,直到线程A结束或者中断。

三、线程的创建方式
1、继承 Thread 类;
2、实现 Runnable 接口,不带返回值;
3、实现 Callable 接口,带返回值,阻塞式获取返回值;

public static void main(String[] args) {
     System.out.println("===开始===");
     //通过结合FutureTask类实现
     FutureTask<String> futureTask = new FutureTask<>(() -> {
         String result = "";
         //结果处理过程......
         result = "Hello world!";
         return result;
     });
     Thread thread = new Thread(futureTask);
     thread.start();
     try {
         //阻塞主线程并获取返回值
         String result = futureTask.get();
         System.out.println("result = " + result);
     } catch (InterruptedException | ExecutionException e) {
         e.printStackTrace();
     }
     System.out.println("===结束===");
}

4、通过线程池创建线。注意:Java原生线程池(阿里官方不推荐使用Executors),原因如下:
在这里插入图片描述

线程池

1、线程池的核心参数
(1)corePoolSize:核心线程数。
(2)maxinumPoolSize:最大线程数。
(3)keepAliveTime:空闲线程存活时间。
(4)unit:时间单位(秒、分钟等)。
(5)workQueue:任务队列,存放任务的容器。
(6)threadFactory:线程工厂,可以使用默认的,或自定义的,通常使用默认。
(7)handler:拒绝策略,顾名思义,拒绝线程访问,JKD自带共有四种策略,如下表:

拒绝策略名称描述
new ThreadPoolExecutor.AbortPolicy()丢弃任务,并抛出RejectedExecutionException异常
new ThreadPoolExecutor.DiscardPolicy()丢弃任务,但是不抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy()丢弃队列最前面的任务,然后重新提交被拒绝的任务
new ThreadPoolExecutor.CallerRunsPolicy()该任务被线程池拒绝,由调用 execute() 方法的线程执行该任务。如果执行程序已关闭,则会丢弃该任务

2、如何设置线程池参数

public static void main(String[] args) {
    //计算CPU核数
    int cpuCores = Runtime.getRuntime().availableProcessors();
    ThreadPoolExecutor threadPool = new ThreadExecutor(
            corePoolSize,   //核心线程数
            maxinumPoolSize,  //最大线程数,CPU密集型即高并发(一般为CPU核数),IO密集型(一般为:CPU核数*2)
            keepAliveTime,  //空闲线程的存活时间
            unit,  //超时时间单位
            workQueue,  //工作队列:new LinkedBlockingDeque<>(3),阻塞队列
            threadFactory,  //Executors.defaultThreadFactory(),默认创建线程的工厂,一般不动
            handler  //拒绝策略:ThreadPoolExecutor.AbortPolicy(),队列满了还有任务直接抛出异常
    );
}

3、线程池的状态及说明
线程池的状态及说明
4、线程池中的提交优先级和执行优先级
参考文章https://blog.51cto.com/u_15891990/5908010
(1)提交优先级: 核心线程 > 工作队列 > 非核心线程
(2)执行优先级: 核心线程 > 非核心线程 > 工作队列

Java锁机制

视屏地址:B站讲的最好的Java锁机制

java线程模型

一、java线程模型,参考文章:https://www.cnblogs.com/songgj/p/15390160.html

java锁分类

参考文章:
方式一、彻底理解Java中的21种锁
方式二、彻底理解Java中的21种锁

轻量级锁

一、CAS(Compare And Swap):比较并交换。也被称为:乐观锁、自旋锁。参考文章:https://blog.csdn.net/weixin_43715214/article/details/128255225

重量级锁

一、synchronized 关键字(非公平锁) 参考如下文章:

1、深入理解 synchronized(一):https://blog.csdn.net/weixin_43715214/article/details/128608153

2、深入理解 synchronized(二):https://blog.csdn.net/weixin_43715214/article/details/128628524

3、synchronized 锁升级过程:
在这里插入图片描述
4、分段式CAS:LongAdder。参考文章:https://www.ngui.cc/el/1845495.html?action=onClick

ReentrantLock 底层原理与源码深度解析

1、参考视屏:B站讲的最好的Java锁机制【P8 - P13】
2、参考文章:深入ReentrantLock实现原理和源码分析

一、ReentrantLock 公平锁与非公平锁

1、ReentrantLock 公平锁与非公平锁,参考文章:https://zhuanlan.zhihu.com/p/45305463

2、ReentrantLock 中的 lock() 与 tryLock() 方法的区别

public class Test {

    private static ReentrantLock reentrantLock = new ReentrantLock();

    public static void main(String[] args) {

        //阻塞式加锁,业务代码不会执行
        reentrantLock.lock();

        //非阻塞式加锁,可以根据尝试加锁是否成功来决定执行逻辑。通常结合while实现自旋
        boolean tryLockResult = reentrantLock.tryLock(); 
        /*
            业务代码 .....
        */
    }
}

ReentrantReadWriteLock 深入理解读写锁

参考文章:深入理解读写锁ReentrantReadWriteLock
参考案例:https://blog.csdn.net/wujian_csdn_csdn/article/details/114385796

CountDownLatch

CounDownLatch 表示计数器,可以给 CountDownLatch 设置一个数字,一个线程调用 CountDownLatch 的 await() 方法将会阻塞,其他线程可以调用 CountDownLatch 的 countDown() 方法来对这个共享计数器中的数字减一,当数字被减成 0 后,所有的 await 的线程都将被唤醒。对应的底层原理就是,调用 await() 方法的线程就会领用AQS排队,一旦数字被减为 0 ,则会将 AQS 中排队的线程依次唤醒。(建议参考源码

semaphore 实现公平锁与非公平锁

Semaphore 表示信号量,可以设置许可的个数,表示同时允许最多多少个线程使用改信号量,通过 acquire() 来获取许可,如果没有许可可用则线程阻塞,并通过 AQS 来排队,可以通过 release() 方法来释放许可,当某个线程释放了许可后,会从 AQS 中正在排队的第一个线程开始一次唤醒,直到没有空闲许可。(其中公平与非公平两种方式建议参考源码

线程死锁与避免死锁

一、如何查看线程死锁:https://blog.csdn.net/fengsheng5210/article/details/123576559

二、MySQL如何查看死锁:https://blog.csdn.net/wufagang/article/details/125554792

三、java如何避免死锁,造成死锁的四个必要条件如下:
1、互斥:一个资源每次只能被一个进程使用。
2、请求且保持:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、资源不可剥夺:进程已获得的资源,在末使用完之前,不能强行剥夺。
4、循环等待:若干进程之间形成一种头尾相接的循环等待资源关系。
注意:避免死锁只需要破坏其中一个条件就可以避免死锁,而其中前 3 个条件是作为锁要符合的必要条件,所以避免死锁就需要打破第 4 个条件(循环等待)
在开发过程中的注意事项:
1、注意加锁的顺序,保证每个线程按同样的顺序进行加锁。
2、加锁的时间,可以针对锁设置超时时间。
3、检查锁循环等待,避免死锁。

Java 容器(Collection、Map)

Java容器知识点:建议参考源码及网络资料深入理解。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌守

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值