Java多线程知识点总结

多线程
1.interrupt 可以中断wait()等待中的线程 也可以对其线程打一个中断标记 注意是使用当前线程来调用此方法 --》此只争对线程
2.wait方法中可以设置参数表示在规定的时间内停止等待
3.在多个线程的情况下 等待结束后如果不在进行判断 则可能会导致读取不到而产生异常 使用while循环再次判断
4.假死:在多线程的情况下所有的线程都进入了wait()状态 解决:使用notifyAll方法
5.脏读:就是一个线程对共享数据的修改另一个线程看不到 原因:对数据的修改一直保存在写缓冲器上或者cpu直接从寄存器中读取数据
6.死锁:两个线程中锁嵌套获取 (两个锁)且两个锁中的获取取顺序不i一样会导致死锁(鹬蚌相争)
7. 原子类
1.基础数据型 AtomicInteger AtomicLong AtomicBoolean直接new对象然后调用相关方法进行递增
2.数组型 AtomicIntegerArray 先进行new一个原子类数组对象然后对其进行相关操作
3.引用对象 AtomicReference() 指定范型 new对象 然后进行操作 注意此方法 compareAndSet
1.AtomicStampedReference () 解决CAS问题 通过版本号
4.字段更新器 AtomicIntegerFieldUpdater
1.是对一个类中元素的操作 此类必须使用volatile关键字修饰
2.不能直接new此对象 它中用一个静态方法 可以创建对象

8.单例设计模式:
构造方法私有化
在类中使用静态方法进行new对象 且私有化
定义方法获取此静态方法new的对象

9.ThreadLocal
1.作用:可以在每个线程分配一个一个对象 (在外面构造ThreadLocal对象
这个对象默认是空的 可以继承该类来重写initialValue 来返回默认的对象 注意在每个线程中使用ThreadLocal的get方法
是都会新生成一个此类中的对像)
2.线程安全:当多个线程同时抢用一个对象时
3.这个对象可以保证每一个线程都有一个对象 使之线程之间不在抢用一个对象

10 可重入性:在锁中需要再次获取该锁对象
11 ReentrantLock 方法 Lock 和 unLock (使用前需要new 一个ReentrankLock对象 然后由该对象调用锁方法)
1.lockInterruptibly锁可以使用线程调用interrupt方法来中断当前线程如果没有获取到锁的时的线程
2.isHeldByCurrentThread 是ReentractLock的方法 可以判断该锁是否被当前线程获取
3.如没有获取到锁且又调用了释放的方法时会产生错误
4.一般使用isAlive方法来判断当前线程的状态
5.tryLock()的无参和有参
1.有参 传入等待时间(这里以秒为单位)在规定的时间内如果没有获取到锁则放弃获取锁
2.无参 第一时间如果没有获取到锁则放弃
12.在多线程的情况下如果不使用锁 可能会导致每个线程之间的共享数据读取不到 从而产生线程安全问题
13.Condition 类可以实现在Lock锁中实现等待唤醒机制
1.构造方法:使用Lock.newCondition()类来获取方法
2.await()同wait一样实现等待
3signal, signalAll 方法 唤醒
4.必须在lock锁中实现
14.在try finally中就算try中程序结束finally中的 也会被执行
15.公平锁与非公平锁
1.synchronized 是一个非公平锁 使用ReentrantLock(是Lock的实现类)默认为非公平锁 当传入一个参数true时可以实现公平锁
2.非公平锁是由系统随机调度的 系统会更偏向于已经获得锁对象的线程 效率高成本低
3.公平锁 不会产生线程饥饿 但是维护成本高 效率低
16.ReentrantLock 常用方法
1.getHoldCount 方法 使用锁对象来获取该锁对象被使用的次数

17.接口中常量必须赋值 多态:方法编译看左边运行看右边 变量全看左边

18.注意 Lock只是一个接口 它的实现类对象为ReentrantLock

19.几个常用的方法
1.int getHoldCount()返回当前线程调用lock()方法的次数
2.int getQueueLength()返回正等待获得锁的线程预估数
3.int getWaitQueueLength(Conditioncondition)返回与Condition条件相关的等待的线程预估数
4.boolean hasQueuedThread(Threadthread)查询参数指定的线程是否在等待获得锁
5.boolean hasQueuedThreads()查询是否还有线程在等待获得该锁
6.boolean hasWaiters(Conditioncondition)查询是否有线程正在等待指定的Condition条件
7.boolean isFair()判断是否为公平锁
8.boolean isHeldByCurrentThread()判断当前线程是否持有该锁
9.boolean isLocked()查询当前锁是否被线程持有

20.ReadWriteLock 读写锁 它的实现类对象为ReentrantReadWriteLock
1.获取读锁:锁对象.readLock
2.获取写锁:锁对象.writeLock
3.读锁可以共享 写锁则互斥

21.线程组:
1.获取当前线程的线程组;线程.getThreadGroup()
2.创造线程组:new ThreadGroup(指定父, 设置名称)
3.在子线程下创建线程:new Thread(线程组,Runnable, 线程名称)
4.如果不指定默认为main线程
5.线程组.interrupt()方法可以给每个线程组打一个标记(如是是睡眠中的线程那么他会抛出异常同时清除标记)
6.setDenmon设置线程尊为守护线程 (注意只有当守护线程中的所有线程执行完之后才能结束程序)

22.线程的异常:
1.在所有情况下除了运行时异常的所有异常产生时 JVM会调用Thread类的dispatchUncaughtException(Throwablee)方法,
该方法会调用getUncaughtExceptionHandler().uncaughtException(this,e)
设置时会根据自己对异常的处理进行打印 如果找不到设置的异常JVM 会自动抛出System.Err
2.//1)设置线程全局的回调接口
Thread.setDefaultUncaughtExceptionHandler(newThread.UncaughtExceptionHandler(){
@Override
public void uncaughtException(Threadt, Throwablee){
//t参数接收发生异常的线程,e就是该线程中的异常
System.out.println(t.getName()+“线程产生了异常:”+e.getMessage());
}
});

23.注意Hook线程: 它在JVM执行结束的时候由JVM自动调用(如果手动结束则不会调用)
1.注入方法:Runtime.getRuntime().addShutdownHook(new Thread()) 它只是调用

24.线程池的工作原理:事先创造指定的线程,然后向线程池提交任务,工作线程会从阻塞队列中执行提交的任务

25线程池的创建方法:
1 ExecutorService es = Executors.newFixedThreadPool(线程数)
2.ExecutorService和ScheduledExecutorService是依赖关系,并不是继承关系
3.ExecutorService的提交任务方法为 submit()和 execute方法
4.ScheduledExecutorSrevice 接口的三个提交任务的方法
1.schedule 在设置的时间后执行任务
2.scheduleAtFixedRate()固定频率的执行任务 当任务时间大于等待时间时他将任务执行完之后直接重新开启线程
3.scheduleWithFixedDelay()当任务执行时间大于等待时间时 它也会在任务执行完之后在等待规定的时间

5.ThreadPoolExecutor的构造方法:
	public ThreadPoolExecutor(
	int corePoolSize,  // 线程池的基本大小(当需要执行任务时如果线程数小于基本大小的话他会先创建在执行)
	int maximumPoolSize, // 线程池中存放的最大线程数
	long keepAliveTime,
	Time Unitunit,
	BlockingQueue<Runnable> workQueue,
	ThreadFactory threadFactory,
	RejectedExecutionHandler handler)
6.有界队列:
	可以指定它的容量 在执行时如果线程数(表示外界开启的线程数量 (任务也相当于一个个线程))小于核心线程数时它将创建线程来执行
	注意:线程池刚开始并没有线程 当执行任务时创建新的线程来执行直到线程数量达到核心线程数时不在创建(任务队列满除外)
	当线程数大于核心线程数时 将其任务加入等待队列中
	当如果队列满的情况下 会先判断是否达到了最大线程数 如果没有则创建新的线程取执行 如果有则执行拒绝策略
7.无界队列:
	可以将其任意多的任务进行等待
8.SynchronousQueue 该线程池在极端情况下,每次提交新的任务都会创建新的线程执行.适合用来执行大量耗时短并且提交频繁的任务

26.拒绝策略:
AbortPolicy策略,会抛出异常CallerRunsPolicy策略,只要线程池没关闭,会在调用者线程中运行当前被丢弃的任务
DiscardOldestPolicy将任务队列中最老的任务丢弃,尝试再次提交新任务
DiscardPolicy直接丢弃这个无法处理的任务
Executors工具类提供的静态方法返回的线程池默认的拒绝策略是AbortPolicy抛出异常,如果内置的拒绝策略无法满足实际需求,可以扩展RejectedExecutionHandler接口

27.在Executors中的三个返回ExecutorService方法都对其ThreadPoolExecutor进行了封装(三个方法的使用场景不同,具体看源码)
可以通过ThreadPoolExecutor 进行自定义线程池
自定义拒绝策略使用new RejectedExecutionHandler()方法

28.线程池中线程的创建:
new ThreadFactory()注意Runnable必须使用它传过来的 否则将无法执行提交的任务
我们重写ThreadFactory时只能说在他创建的时候干一些事, 并不能修改线程中的内容

29线程池监控: 具体查看ThreadPoolExecutor文档
监控线程池ThreadPoolExecutor提供了一组方法用于监控线程池
int getActiveCount()获得线程池中当前活动线程的数量
long getCompletedTaskCount()返回线程池完成任务的数量
int getCorePoolSize()线程池中核心线程的数量
int getLargestPoolSize()返回线程池曾经达到的线程的最大数
int getMaximumPoolSize()返回线程池的最大容量
int getPoolSize()当前线程池的大小
BlockingQueue getQueue()返回阻塞队列
long getTaskCount()返回线程池收到的任务总数

30.在任务提交执行前执行beforeExecute方法执行完之后执行afterExecute
查看ThreadPoolExecutor源码,在该类中定义了一个内部类Worker,ThreadPoolExecutor线程池中的工作线程就是Worker类的实例,
Worker实例在执行时会调用beforeExecute()与afterExecute()方法

31.在线程池中存在异常情况被吃掉的情况

  • 1.将其submit方法改为execute
  • 2.进行线程池的扩展
  • 3.在try中捕获的异常必须进行处理不能进行抛出

32.ForkJoinPool 线程池 采用分而治之的思想 将一个大任务分解成小任务执行
1.在ForkJoinTask中 本身是一个任务 如果需要分解 则需要重新在该类中new 一个本身 然后使用fork进行提交
2.ForkJoinTask有两个重要的子类:RecursiveAction和RecursiveTask,
它们的区别在于RecursiveAction任务没有返回值,RecursiveTask任务可以带有返回值
3.compute()需要重写此方法
4.使用此线程池的大致步骤:
1.创建任务类 ForkJionTask
1.判断是否需要分解
1.需要则重新new 本身然后进行提交
2.new 线程对象
3.new 任务类对象
4.进行提交
5.在此线程池中每个线程对应都有一个队列 队列中有多个任务
且系统进行了优化当线程a执行完任务之后如果b还没执行完那么a会从队列的最低层取任务执行

6.注意,如果任务划分的层次很深,即THRESHOLD阈值太小,每个任务的计算量很小,层次划分就会很深,可能出现两种情况:
	一是系统内的线程数量会越积越多,导致性能下降严重;
	二是分解次数过多,方法调用过多可能会导致栈溢出

33.实例变量和实例对象的区别

34偏向锁:当只一个线程且需要不断的获取锁和释放锁时 JVM会优化 使之下次不用获取锁 提高了效率
原理:在锁的对象头中有一个Threadid字段在没有线程访问时该字段为空 当第一个线程访问且并没有其他的线程访问
这时JVM会让其持有偏向锁 并将其Threadid的值设置为线程的id下次访问时只需判断该id
35.轻量级锁: 交替执行 不进入阻塞状态 提高响应率 如果线程没有获得锁则处于自旋状态当超过一定 的时间就会将其转变为重量级锁
36.重量级锁:多个线程抢用锁时没有获得锁的线程将进入阻塞状态
37.乐观锁:总是假设最好的情况 在每次拿锁的时候并不会对其共享资源上锁,只有当其修改数据时才进行CAS判断 使用与多读的操作
38.悲观锁:总是假设最坏的情况 在每次拿数据的时候都会对其上锁是别的线程无法访问 只有当其他线程获得锁时才可以访问
且同时只能一个线程访问,其他线程进入阻塞状态
39.装饰器模式:
1.在java.util.Collections工具类中提供了一组synchronizedXXX(xxx)可以把不是线程安全的xxx集合转换为线程安全的集合,
它就是采用了这种装饰器模式.这个方法返回值就是指定集合的外包装对象.这类集合又称为同步集合
2.使用装饰器模式的一个好处就是实现关注点分离,在这种设计中,实现同一组功能的对象的两个版本:
非线程安全的对象与线程安全的对象.对于非线程安全的在设计时只关注要实现的功能,对于线程安全的版本只关注线程安全性
3.使用其包装是将其已经创建的对象放入其中进行包装为线程安全的对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

时越zz

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

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

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

打赏作者

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

抵扣说明:

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

余额充值