线程基本信息详解

线程的五种状态

创建: 新建一个线程对象
就绪:线程调用 start() 方法, 变得可运行,等待 CPU资源
运行:线程获取 CPU资源,执行程序代码;
阻塞:线程应为某种原因放弃CUP资源,暂时停止运行,直至线程再次进入就绪状态,才有机会运行;
死亡: 线程执行完成或者 异常退出 run()方法,该线程结束生命周期;

线程的三种阻塞情况

等待阻塞: 运行的线程执行 wait(),线程会释放资源,JVM会把线程添加到’等待池’中,该种情况线程不能自动唤醒,需要调用 notify()或者notifyAll()才能唤醒;wait()是object的方法;
同步阻塞: 运行线程在获取对象同步锁时,若该同步锁被其他线程占用,则JVM将该线程放入到 ‘锁池’中;
其他阻塞: 运行线程执行 sleep(), join(),或者发生 I/O请求时,JVM会将线程设置成阻塞状态,当sleep超时,join等待结束或者超时,I/O执行完成时,线程会进入到就绪状态; sleep()是 Thread 的方法;

sleep(),wait(), yeid(), join() 的区别

锁池 : 所有需要竞争同步锁 (synchronized)的线程才会放入到 '锁池’中;例如,当线程B去获取同步锁时,发现同步锁已经被 A线程 占用,那么线程B就会进入‘锁池中’;
等待池: 当线程 执行 wait() 方法时(使用wait()方法必须是在 synchronized中),该线程会被放入到 ‘等待池’中,等待池中线程是不会去竞争锁的; notity() 方法是唤醒等待池中的随机的一个线程,notityAll()方法是唤醒等待池中所有的线程,被唤醒的线程进入锁池中,参与竞争同步锁;
1: sleep() 方法是 Thread的方法,线程调用该方法时,暂停执行,但不会释放锁,但会把CPU的执行权释放出去,当sleep()结束后会再次获取 CPU的执行权,继续执行;
2: wait() 方法时 object 类的方法,线程调用该方法时,暂停执行,但会释放锁,只有当该线程被notity() 或者 notityAll() 唤醒时,线程会进入到 锁池中, 参与锁的竞争,只有竞争到锁后才能继续执行; wait() 方法多用于线程之前的通信;
3: 线程 执行 yeid() 方法后会让出 CPU资源,但该线程仍然有CUP的执行资格,所有有可能下次CPU执行调用还会调用这个线程使其继续执行;
4: join() 方法执行后线程会进入阻塞; 例如线程 B中调用 A线程的 join()方法,线程B会进入阻塞队列,直至线程A执行完或者中断,线程B才会继续执行; 如下图:join()方法执行后 main线程进入到阻塞,当 t1 线程执行完后才执行 main()线程中的程序;

对线程安全的理解

线程安全实际上也就是内存安全,例如单个线程执行某个程序的结果与多个线程执行的结果是同样的,无差别的,那么这个多线程就是安全的;堆是共享内存,所有线程共有的,栈是每个线程私有的,每个线程都有自己的栈;

守护线程的理解
为所有非守护线程提供服务的线程; 守护线程中产生的新线程也是一个守护线程,GC垃圾回收线程,就是一个经典的守护线程;

为什么使用线程池
1: 降低资源消耗,提高线程利用率,降低线程的创建与销毁的消耗;
2:提高线程的可管理性,通过线程池对线程进行统一的调配与管理;
3:提高响应速度,当任务来时,不用进行线程创建,可直接用线程池的中的线程处理任务;

线程池参数

corePoolSize: 核心线程数,也就是正常情况下创建工作的线程,这种线程创建后不会被消除,是一种常驻线程;
maxinumPoolSize: 最大线程数,它与核心线程数想对应,表示最大被创建的线程数;比如,任务较多时,核心线程数用完了,还无法满足需求,并且阻塞队列也放满,那么就会创建新的线程,但是线程池的线程总数不会超过最大线程数;
keepAliveTime unit : 核心线程不会被消除; 该参数作用于非核心线程,通过设置空闲时间方法为 setKeepAliveTime,当非核心线程空闲一定时间时,就会被消除;
workQueue: 用于存放执行的任务,当核心线程都已经被占用,再来任务时,任务会放入到队列中,当队列放满时再创建新的线程;
ThreadFactory: 线程工厂,用来生产线程执行任务;若选择默认工厂,则生产的线程会在同一个组中,同一优先级,且不是守护线程;也可以根据业务自定义线程工厂;
Handler: 拒绝策略,一种情况是 调用 shutdown()方法,即使线程池中还有在执行的任务,我们再提交任务到线程池也会遭到拒绝;第二种情况是当达到最大线程数时,还是没有能力处理提交的任务时,也会遭到拒绝;

线程池中阻塞队列的作用

一般队列:
只能保证作为一个有限长度的缓冲区,假如队列长度 10,当第11个任务来时,就无法保留当前的这个第11个任务;

阻塞队列:
1)当第 11个任务来时,队列通过阻塞保留住这个任务;
2)当任务队列中无任务时,阻塞队列阻塞获取任务的线程,使线程进入到 wait 状态,释放 CPU资源;
3)阻塞队列自带阻塞和唤醒功能,不需要额外的处理;当无任务时,线程利用阻塞队列的 take()方法挂起,从而维持核心线程的存活,不至于一直占用 CPU 资源;

为什么是先添加队列而不是先创建最大线程
创建线程的时候需要获取全局锁,这个时候其他的就需要进入到阻塞,影响了整体效率;
例如: 线程池核心线程数为 5,最大线程数为10,当前核心线程都在执行任务,这时第 6个任务来了,那么线程池也不会创建新的线程,而是现将第 6个任务 放到阻塞队列中,当阻塞队列放满时,还有任务来,那么才开始创建最大线程数来执行 任务;
为什么不在 第6个任务来时就创建新的线程呢: 因为核心线程数就是对着正常任务数量设置的,而最大线程数时对着任务量的 峰值设置的,假如当第6个任务来时,就创建新的线程,那么第6个任务执行完,新建的任务超过设置的空闲时间就会被消除,为了一个任务创建新的线程严重消耗了CPU的资源; 线程池的作用就是为了避免 频繁的创建,消除线程而消耗资源的;

线程的复用原理
线程与任务时解耦的,线程时线程,任务时任务,不是再通过 start()方法去调用,而是线程去循环执行 队列中的任务,将 run()方法当成一个普通方法,将所有任务的 run()方法串联起来;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值