多线程
概念:线程是程序执行的最小单位,每个进程最少有一个线程,线程必须依赖进程。线程同步:当多个线程同时访问同一份可变的共享资源的时候,为了保证数据的一致性,安全性,完整性,考虑用线程同步。
生命周期
新建:用new创建了一个线程对象。
就绪:调用了start()方法。
运行:获得cpu资源,执行run()方法里的代码。
阻塞:调用了yield():只会给优先级相同或者更高的线程执行的机会(不会进入阻塞状态而是直接进入就绪状态)。
死亡:线程执行完成,或者是线程抛出了一个没有捕获的异常
创建方式
继承thread类重写run()方法。
实现Runnable接口重写run()方法。
实现Callable接口重写call()方法。
说明
开启一个线程要调用run()对应的start()方法,如果直接调用run()方法只是调用了一个没有生命周期的普通方法。
继承thread和实现Runnable的区别,由于java是支持单继承多实现,所以推荐使用实现Runnable,可以增加代码的健壮性,实现Runnable接口,代码与数据是独立的。
sleep()和wait()的区别
sleep() 方法:线程主动放弃CPU,使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。典型地,sleep() 被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。
wait( ) :与notify() 配套使用,wait()使得线程进入阻塞状态,它有两种形式,一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数,当指定时间参数时对应的notify() 被调用或者超出指定时间时线程重新进入可执行状态,后者则必须对应的notify() 被调用。
适用场景当需要提高cpu的工作效率时使用多线程
优缺点
优点:可以提高cpu的使用率,提高程序的工作效率
同步线程安全但效率不高,异步线程不安全但工作效率高
缺点:当有多个线程同时访问cpu会消耗大量的资源,会影响性能,因为cpu要在它们之间切换,多线程同时访问cpu还可能造成线程死锁(两个线程以相反的顺序申请两把锁)
四种线程池以及它们的应用场景:
1、FixedThreadPool:这类线程池里全部都是核心线程,线程数固定,且不被回收,线程和线程池的生命周期同步,适用于任务量固定且耗时长的任务。
2、CachedThreadPool:这类线程里面全部都是非核心线程,线程和无限创建,有60秒的有效期,当闲置的线程有效期没被使用,就会被回收,适合任务量大且耗时少的任务。
3、ScheduledThreadPool:这类线程核心线程是固定的,非核心线程是没有限制的且一闲置就会被回收,这类线程池适用于执行定时任务和具体固定周期的重复任务。
4、SingleThreadPool:只有一个核心线程,适用于多个任务顺序执行。