多线程知识汇总

    多线程:
        线程的创建:
            1.继承thred类,
            2.实现runnable接口,

        线程的启动:
            使用start()方法,会产生两个线程
            使用run()方法,产生一个线程

        线程的5种状态(生命周期):
            1.新建(创建了线程对象),
            2.就绪(调用了start方法或从阻塞状态唤醒),
            3.运行(分配了cpu时间片),
            4.阻塞(做io操作或sleep),
            5.死亡(线程执行结束后)

        线程安全:
            多线程访问时,采用加锁机制,当一个线程访问该类的某个数据时进行保护,其他线程不能访问直到该线程读取完其他线程才可使用。

        线程的锁机制:
            锁大致可以分为互斥锁,共享锁和读写锁

            互斥锁:只有一个线程可以访问被保护的资源,在访问共享对象之前,对其进行加锁操作,在访问完成后进行解锁操作。加锁后,其他试图加锁的线        程会被阻塞,直到当前线程解锁。解锁后,原本等待状态的线程变为就绪状态,重新竞争锁

            1)synchronized和reentrantlock都是典型的互斥锁,synchronized是jvm关键字,不用处理异常状态下的锁释放,当资源使用完毕后,连接断开时        会自动释放;而reentrantlock是java类,需要显式调用释放锁

            reentrantlock实现了lock接口,底层基于AQS(AbstractQueuedSynchronizer)实现,AQS为加锁和解锁过程提供了统一的模版函数。
        在Reentrantlock中,它将AQS的state状态值定义为线程获取该锁的重入次数,state为0表示当前没有被任何线程持有,state为1表示被其他线程持        有,因为支持可重入,如果是持有锁的线程,再次获取同一把锁,直接成功,并且state的值+1,线程释放锁state的值-1,同理重入多次锁的线程需要释        放相应的次数。

            可重入锁:一个线程获得一个锁,在重复的获取这个锁的时候直接成功,注意是重复获取相同的锁。reentrantlock和synchronized都是可重入锁。
            
            共享锁:允许多个线程共同访问资源

            读写锁:renntrantreadwritelock,既是互斥锁又是共享锁,在读模式下是共享锁,在写模式下是互斥锁
            
        扩展:
            公平锁:根据先进先出的规则,从等待队列中取出第一个等待线程获取锁
            非公平锁:与公平锁相反,新来的线程在一上来就会尝试占有锁,如果这时候刚好在发出请求时锁变成可用状态,则这个线程会跳过队列中的等待线        程直接获取锁,否则,将自己加入到队列中
            可中断锁:即等待锁的过程中时可以中断的。在互斥锁中,synchronized是不可中断的,而reentrantlock是可以中断的(提供了trylock和        lockinterruptibly两种方法来中断等待操作)
            悲观锁:每次去拿数据的时候都认为别人会修改,所以每次拿数据的时候都会上锁。(数据库的行锁,表锁,读写锁)
            乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁。但在更新的时候会判断一下在此期间有没有人更新了这个数据(实现方式有版本        号等方式)
            死锁:指两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象。当一个线程永久的持有一把锁后,其他线程将一直等待下        去    
            注意⚠️:
                形成死锁的四个条件:
                1)互斥性:即线程占用的锁是互斥锁,不能被其他未占有的线程访问
                2)不可剥夺:即线程已经获得锁,在未主动放弃之前不会被其他线程剥夺
                3)请求和保持:即有锁s1和s2,线程一持有s1,有发起了对s2的持有请求。而同时线程二持有了s2,又对s1发起了持有的请求。
                4)环路等待:即死锁发生时必然有一个环形链,如(p1,p2,p3),p1等待p2释放资源,p2等待p3释放资源,p3等待p1释放资源。    
            锁实现:CAS算法

        线程池的使用:(threadpoolexector)
            参数说明:
            public ThreadPoolExecutor(
                                       int corePoolSize,             核心线程数
                                                     int maximumPoolSize,    最大线程数
                                                        long keepAliveTime,        非核心线程的存活时间
                                                     TimeUnit unit,                  时间单元
                                                        BlockingQueue<Runnable> workQueue,      任务队列
                                                       ThreadFactory threadFactory,                        线程工厂
                                                        RejectedExecutionHandler handler               拒绝策略(默认的是终止策略)
            )

            注意⚠️:提交优先级:首先提交到核心线程,其次是队列,再是非核心线程
                      执行优先级:首先执行核心线程中的任务,其次是非核心线程中的,再是队列中的
            
            队列:
                同步队列(SynchronourQueue):直接提交,不会保存任何任务
                无界队列(LinkedBlockingQueue):对于新加入的任务全部存入队列当中,任务太多的话会导致内存溢出(OOM)
                有界队列(ArrayBlockingQueue):队列有一个最大值,超过最大值的任务交给拒绝策略来

            拒绝策略:
                       AbortPolicy(终止策略):如果线程池线程被用完了,队列也放不下了,直接抛出异常 rejectedExecution从而终止任务;
                DiscardPolicy(丢弃策略):如果线程池的线程被用完了,队列也放不下了,不抛出异常,直接丢弃多余的任务;
                DiscardOldestPolicy(丢弃最老策略):如果线程池的线程被用完了,队列放不下了,就把等待时间最久的任务丢弃
                CallerRunsPolicy(呼叫者运行策略):如果线程池的线程全部被用完,队列放不下的时候,会把多余的任务返回给调用者(主线程)去执行

            堵塞线程池和非堵塞线程池:(使用有界队列和呼叫者运行策略,)

                堵塞线程池:在拒绝策略中将新进入的任务再次放入队列中,用put方法,如果满了就会一直等待直到队列中的其他任务被释放
                    优点:不会出现消息丢失和内存溢出的问题
                    缺点:把线程池的压力交给了主线程来处理,如果消息量过高,主线程得不到响应,会报出超时异常

                非堵塞线程池:在拒绝策略中将新进入的任务进行存储,后续进行处理
                    优点:不会造成内存溢出,也不会堵塞
                    缺点:设计复杂

            线程池的使用场景:
                1.异步处理日志;
                2.定时任务(定时发送邮件,定时对数据库备份)
                3.数据迁移

            线程池的优点:
                1.减少频繁的创建和销毁线程
                2.充分利用cpu,提高系统的运行效率

            线程池线程数的设计:
                线程数=处理器的核的数目*cpu利用率*(1+w/c)
                w:等待时间
                c:计算时间

            executors下的五种创建线程池的方法:
                1)、newCachedThreadPool:返回一个可以根据实际情况调整非核心线程数量的线程池,会出现cpu100%,使用的是同步队列;
                      2)、newFixedThreadPool:该方法返回一个固定核心线程数量的线程池,会出现内存溢出,使用的是一个基于链表的阻塞队列;
                          3)、newSingleThreadExecutor:该方法返回一个只有一个线程的现成的线程池,会出现内存溢出,使用的是一个基于链表的阻塞队列;
                      4)、newSingleThreadScheduledExecutor:该方法和newSingleThreadExecutor的区别是给定了时间执行某任务,可以进行定时执行等;
                      5)、newScheduledThreadPool:在4的基础上可以指定线程数量。


        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值