(原创)学习资料-多线程相关

发布时间:2026/7/22 8:08:40

(原创)学习资料-多线程相关 资料来源黑马java视频线程的几种状态参考博客参考视频一共六种NEW初始化态线程被创建RUNNABLE运行态又分为就绪状态和运行中两个状态BLOCKED阻塞态线程阻塞于锁在外面等待的时候称为阻塞态有且仅有synchronized才能进入这个状态如果是Lock的话进入的是等待或者等待超时WAITING等待状态拿到锁后发现不符合运行条件需要暂停执行比如调用wait让出锁或者condition.await()让出cpu资源 供其他线程执行TIMED_WAITING超时等待等待固定时间在时间到达后自行返回相比于等待状态需要其他条件唤醒这个状态可以做到根据时间自行唤醒TERMINATED结束态线程结束线程状态可以看下图解决多线程安全问题的几种方式1同步代码块synchronized (对象锁旗标){//需要被同步的代码}2同步函数Synchronizedvoid方法名注意同步函数的锁旗标是他本身的对象引用也就是this静态同步函数的锁旗标是该方法所在类的字节码文件对象也就是类名.class锁的弊端多线程时需要判断锁较为消耗资源3Lock 和 ConditionJava1.5以后加入了Lock 和 Condition更加显性的给线程进行同步控制使用方法如下LocklocknewReentrantLock();lock.lock();try{//写你的同步代码}catch(Exceptione){}finally{lock.unlock();}Condition主要是用来对线程进行睡眠和唤醒的操作替代waitnotifynotifyAlllock.newCondition()方法可以得到一个Condition对象他有几个方法condition.await(); 线程等待condition.signal(); 线程唤醒condition.signalAll(); 唤醒这个锁的所有线程另外还可以多次调用newCondition返回多个Condition对象每个对象调用自己的await和signal进行等待和唤醒操作这样可以做到对指定的Condition对象进行等待和唤醒操作conditionA调用await只能用conditionA的signal来进行唤醒sleep和waitSleeptime让线程进入睡眠状态传入一个时间时间到了线程重新唤醒Sleep 不会释放锁资源wait,notify,notifyAll方法介绍他们都使用在同步函数或者同步代码块中功能是对持有锁的线程进行等待或者唤醒操作因为只有同步才具有锁。所以要使用在同步中只有同一个锁上的被等待线程可以被同一个锁上 notify 唤醒不可以对不同锁中的线程进行唤醒。也就是说等待和唤醒必须是同一个锁旗标。因为锁旗标可以是任意对象所以可以被任意对象调用的方法定义 object类中wait会释放锁资源死锁两个线程A和B在同步的时候互相持有对方的锁A需要B的锁才能继续执行B需要A的锁才能继续执行这样就导致了死锁一般是同步嵌套同步容易导致死锁开发时需要注意避免死锁避免死锁的方式可以利用好Lock.tryLocksleep的方法这个方法是尝试拿锁拿锁成功返回true拿锁失败返回false这样就可以成功避免死锁sleep主要是为了放开资源避免单个线程重复拿到锁如下面两个图停止线程的方法线程只有执行完Run方法才会结束不推荐调用stop的方法去停止线程因为容易导致死锁等问题虽然不能停止但是java提供了中断线程的方法interrupt设置当前线程状态为中断状态配合另外两个方法一起使用isInterrupted判断线程是否中断这样就可以根据这个状态来做实际的逻辑interrupted判断线程是否中断判断完之后会将线程的中断状态清除就是如果线程被interrupt方法设置线程中断了第一次调用会返回true并且清除掉中断状态第二次调用除非再次调用interrupt方法设置线程中断不然就会返回false。Join方法线程A调用这个join方法会抢夺当前线程B的执行权A线程执行完了之后才会把执行权重新还给B比如主线程中创建了一个新的子线程A然后A.join主线程就会停止往下走直到A线程执行完主线程才会继续往下走这个方法可以用来临时加入一个线程执行Join不会释放锁资源yield方法线程调用自身的这个方法代表让出执行权进入到就绪状态重新抢夺cpu资源yield也不会释放锁资源线程的可见性,原子性,有序性可见性是指当一个线程修改了某一个共享变量的值其他线程是否能够立即知道这个修改。Java线程里有一个主内存和工作内存之分一个子线程会把主内存的变量的值缓存在工作内存之中。故而不同的线程对于同一个变量都有一个自己缓存的值。如果要保证可见性可以加volatile关键字或者synchronized同步以及final原子性严格的原子性的操作其他线程获取操作的变量时只能获取操作前的变量值和操作后的变量值不能获取到操作过程中的中间值在操作过程中其他操作需要获取变量值需要进入阻塞状态等待操作结束。如果要保证原子性可以加synchronized或者锁保证同一时间只有一个线程操作变量有序性在并发时程序的执行可能会出现乱序。给人的直观感觉就是写在前面的代码会在后面执行。有序性问题的原因是因为程序在执行时可能会进行指令重排重排后的指令与原指令的顺序未必一致。有序性可以看这个视频https://www.bilibili.com/video/BV1XT4y1M7E9?p6volatile关键字的作用1、保证可见性2、防止指令重排抑制重排序3、但是不保证原子性volatile的作用就是这样被volatile修饰的变量保证了每次读取到的都是最新的那个值。线程安全围绕的是可见性和原子性这两个特性展开的volatile解决的是变量在多个线程之间的可见性但是无法保证原子性。多提一句synchronized除了保障了原子性外其实也保障了可见性。因为synchronized无论是同步的方法还是同步的代码块都会先把主内存的数据拷贝到工作内存中同步代码块结束会把工作内存中的数据更新到主内存中这样主内存中的数据一定是最新的。synchronized: 具有原子性有序性和可见性volatile具有有序性和可见性线程池四种常见的线程池CachedThreadPool:可缓存的线程池该线程池中没有核心线程非核心线程的数量为Integer.max_value就是无限大当有需要时创建线程来执行任务没有需要时回收线程适用于耗时少任务量大的情况。SecudleThreadPool:周期性执行任务的线程池按照某种特定的计划执行线程中的任务有核心线程但也有非核心线程非核心线程的大小也为无限大。适用于执行周期性的任务。SingleThreadPool:只有一条线程来执行任务适用于有顺序的任务的应用场景。如果线程因为异常而停止会自动新建一个线程补充FixedThreadPool:一个核心线程数跟最大线程数相同的线程池,线程池数量大小不变,如果有任务放入队列,等待空闲线程。工作原理1、线程在有任务的时候会创建核心的线程数corePoolSize2、当线程满了有任务但是线程被使用完不会立即扩容,而是放到阻塞队列中,当阻塞队列满了之后才会继续创建线程。3、如果队列满了,线程数达到最大线程数则会执行拒绝策略。4、当线程数大于核心线程数事,超过KeepAliveTime(闲置时间),线程会被回收,最终会保持corePoolSize个线程。七个核心参数corePoolSize: 线程池核心线程个数workQueue:用于保存等待执行任务的阻塞队列maximunPoolSize: 线程池最大线程数量ThreadFactory: 创建线程的工厂RejectedExecutionHandler: 队列满并且线程达到最大线程数量的时候对新任务的处理策略keeyAliveTime: 空闲线程存活时间TimeUnit: 存活时间单位拒绝策略1、AbortPolicy被拒绝了抛出异常2、CallerRunsPolicy(使用调用者所在线程执行就是哪里来的回哪里去)3、DiscardOldestPolicy(尝试去竞争第一个失败了也不抛异常)4、DiscardPolicy(默默丢弃、不抛异常)拒绝策略执行则么办1、另外创建一个队列,当拒绝策略执行将任务放入队列。通过定时任务去每隔一秒去查看线程池队列中是否有任务,没有则添加进去。缺点: 任务会丢失,线程优雅关闭是指正常情况队列执行晚。会关闭。如果用这种方法创建则会丢失任务。2、如果 是特别重要的话就 放入DB去持久化,给任务加个状态,通过状态来判断任务的执行情况。3、其他情况要根据场景考虑 比如又些任务过期淘汰判断线程池执行完任务https://blog.csdn.net/u013310119/article/details/117926703

相关新闻