1 线程创建方式
1.1 继承Thread类
Thread类本质上是实现类Runnable接口的一个实例,代表一个线程的实例。继承Thread类后,可以通过start()方法启动一个新线程,start()方法是native的一个方法,它会去执行run()方法。
1.2 实现Runnable接口
因为Java是单继承的,如果类本身已经extends了一个类,就无法再继承Thread类,但是可以直接通过实现Runnable接口,implements Runnable接口后,启动线程是直接执行run()方法。
2 线程池
2.1 newCachedRhreadPool
表示创建一个可根据需要创建新线程的线程池。调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有60s未被使用的线程。
2.2 newFixedThreadPool
创建一个可重用固定线程的线程池,以共享的无界队列方式来运行这些线程。
2.3 newSheduledThreadPool
创建一个线程池,它可安排在给定延迟后运行命令或者定期执行。
2.4 newSingleThreadExecutor
这个线程可以在线程死后或者发生异常时,重新启动一个线程来替代原来的线程继续执行下去。
3 线程生命周期(状态)
3.1 新建状态(New)
当程序使用new 关键字创建一个线程后,该线程就处于新建状态,此时由JVM为其分配内存,并初始化成员变量的值。
3.2 就绪状态(RUNNABLE)
当线程对象调用了start()方法之后,该线程就处于就绪状态。此时,JVM会为其创建一个java栈和程序计数器,等待调度运行。
3.3 运行状态(RUNNING)
如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。
3.4 阻塞状态(BLOCKED)
阻塞状态是指线程因为某种原因放弃了CPU使用权,也就是让出了cpu timeslice,暂时停止运行。知道线程进入可运行状态,才有机会再次获得cpu timeslise转到运行状态。
阻塞的情况分为三种:
1)等待阻塞
运行的线程执行wait()方法,JVM就会把改线程放入等待队列(waiting queue)中。
2)同步阻塞
运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
3)其他阻塞
运行的线程执行THread.sleep()或者Threa.join()方法,或者发出了I/O请求时,JVM会把该线程设置为阻塞状态。当sleep()状态超时、join()等到线程终止或超时、或者I/O处理完毕时,线程重新转入运行状态。
3.5 线程死亡(DEAD)
线程结束就是死亡状态,结束方法有以下三种:
正常结束:run()或call()方法执行完成,线程正常结束。
异常结束:线程抛出一个未捕获的Exception或Error。
调用stop:直接调用该线程的stop()方法来结束该线程--容易造成死锁
4 终止线程4种方式
(1)正常运行结束
(2)使用退出标志退出线程
(3)Interrupt方法结束线程
(4)stop方法终止线程(线程不安全)
5 sleep()和wait()的区别
sleep()属于Thread类,wait()属于Object类。
sleep()只是在指定时间暂停,但是它的监控状态依然保持着,时间到就自动恢复运行。
sleep()不会释放对象锁;wait()会释放对象锁。
6 start()和run()的区别
start()方法启动线程,真正实现多线程运行,无需等待run()方法体代码执行完毕便可继续执行下面的代码。
start()方法启动,表示此线程处于就绪状态,没有运行。
run()方法称为线程体,它包含了要执行的这个此线程的内容,即表示线程处于运行状态,开始运行run喊出当中的代码。run()方法运行结束,线程终止。