线程五种状态
new: 可通过implements runnable ;extends thread 创建
runnable:调用start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权
running: 执行代码
blocked: 放弃cpu使用权。
等待阻塞:wait()方法
同步阻塞:获取同步锁时,该锁被占用,被放到锁池中
其他阻塞:运行sleep,join 或发出io请求时。
dead: 执行完成或异常退出
sleep yield join wait区别
sleep:当前线程进入阻塞,但不释放对象锁,millis后线程自动苏醒进入可运行状态
yield:当前线程放弃获取的cpu时间片,由运行状态变会可运行状态,让OS再次选择线程.能不能抢到不管
join:在自己当前线程加入你调用Join的线程(),本线程等待。等调用的线程运行完了,自己再去执行
wait:当前线程释放对象锁,进入等待队列。依靠notify()/notifyAll()唤醒或者wait(long timeout)timeout时间到自动唤醒
notify:唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll()唤醒在此对象监视器上等待的所有线程
implements extends区别
extends:Java是单继承机制,不允许同时继承多个类 implements:多个线程共享一个对象
start run区别
start :变成可执行状态,真正实现了多线程运行
run: 直接执行
多线程就是分时利用CPU,宏观上让所有线程一起执行 ,也叫并发。
synchronized的三种应用方式
1.作用于实例方法,当前实例加锁,进入同步代码前要获得当前实例的锁;
2.作用于静态方法,当前类加锁,进去同步代码前要获得当前类对象的锁;
3.作用于代码块,其中普通代码块 如Synchronized(obj) 这里的obj 可以为类中的一个属性、也可以是当前的对象,它的同步效果和修饰普通方法一样;Synchronized方法 (obj.class)静态代码块它的同步效果和修饰静态方法类似
线程池的实现原理
通过 Executors 的静态方法创建出来的。而他们底层是通过 ThreadPoolExecutor类创建出来的。线程池的几个重要参数分别是:
- corePoolSize:核心线程池的大小。在线程池创建后,其中没有线程。当有任务时,创建线程。当线程数量达到corePoolSize之后,就把任务放到缓存队列当中。
- maximumPoolSize:线程池的最大线程数量。如果未设置,不断创建新线程,最后内存会崩掉。
- keepAliveTime:当线程没有任务时,最多保持的时间,超过这个时间就被终止了,默认值 60 秒。默认情况下,只有线程池中线程数量大于 corePoolSize 时,keepAliveTime 值才会起作用。也就说,只有在线程池线程数量超出 corePoolSize了。我们才会把超时的空闲线程给停止掉。否则就保持线程池中有 corePoolSize 个线程就可以了。
- Unit:keepAliveTime的时间单位。
- workQueue:用来存储待执行任务的队列,不同的线程池它的队列实现方式不同:
- ArrayBlockingQueue:基于数组的队列,创建时需要指定大小。
- LinkedBlockingQueue:基于链表的队列,如果没有指定大小,则默认值是 Integer.MAX_VALUE。(newFixedThreadPool和newSingleThreadExecutor使用的就是这种队列),吞吐量通常要高于ArrayBlockingQuene。
- SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene(newCachedThreadPool使用的就是这种队列)。
- threadFactory:线程工厂,用来创建线程。通过自定义的线程工厂可以给每个新建的线程设置一个具有识别度的线程名。
- Handler:拒绝执行任务时的策略,一般来讲有以下四种策略:
- ThreadPoolExecutor.AbortPolicy (默认的执行策略)丢弃任务,并抛出 RejectedExecutionException 异常。
- ThreadPoolExecutor.CallerRunsPolicy:该任务被线程池拒绝,由调用 execute 方法的线程执行该任务。
- ThreadPoolExecutor.DiscardOldestPolicy : 抛弃队列最前面的任务,然后重新尝试执行任务。
- ThreadPoolExecutor.DiscardPolicy,丢弃任务,不过也不抛出异常。
几种线程池的比较
CachedThreadPool
线程数量无限制,最大数目为Interger.MAX_VALUE,这样可灵活的往线程池中添加线程。如果长时间无任务,线程终止。有任务重新创建。一定要控制任务数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。
FixedThreadPool
创建固定线程数量的线程池。定长线程池的大小最好根据系统资源进行设置如Runtime.getRuntime().availableProcessors()。具有线程池提高程序效率和节省创建线程时所耗的开销的优点。线程池空闲时,不会释放工作线程,还会占用一定的系统资源。
SingleThreadExecutor
创建一个单线程的线程,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
ScheduleThreadPool
创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。
线程池任务的提交流程
- 创建线程池,池中无线程,当有任务到来,且线程池中线程数量<corePoolSize,则创建一个新线程去处理任务。
- 线程池中线程数量=corePoolSize设定(当核心池已经满了),有新任务时,将任务放置到任务队列workQueue中。如果成功,则等待空闲线程将其从队列中取出并且执行,如果队列workQueue已满,则继续下一步。
- 此时,如果线程池线程数量<maximumPoolSize,则创建新线程执行任务,否则,那就说明线程池到了最大饱和能力了,没办法再处理了,此时就按照拒绝策略来处理。(构造函数当中的 Handler 对象)。
- 如果线程池的线程数量> corePoolSize,则当某个线程的空闲时间超过了 keepAliveTime,那么这个线程就要被销毁了,直到线程池中线程数量<= corePoolSize 为止。
线程池的 shutdown 和 shutdownNow 方法的区别
- shutdown 设置状态为 SHUTDOWN,而 shutdownNow 设置状态为 STOP
- shutdown 只中断空闲的线程,已提交的任务可以继续被执行,而 shutdownNow 中断所有线程
- shutdown 无返回值,shutdownNow 返回任务队列中还未执行的任务