随着开发项目中业务功能的增加,必然某些功能会涉及到线程以及并发编程的知识点。笔者就在现在的公司接触到了很多软硬件结合和socket通讯的项目了,很多的功能运用到了串口通讯编程,串口通讯编程的安卓端就是基于线程的方式和硬件保持通讯的。
关于Java线程,先了解一下Java线程的生命周期和物种基本状态,先上一张经典的图
上图也比较直观的绘制了关于Java线程的生命周期同时也囊括了Java线程的重点知识点。
Java线程的五种状态:
新建状态(New):
当线程对象创建后,线程即进入新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):
当线程对象的start()方法(t.start();)调用时,此时线程进入就绪状态。处于就绪状态的线程只能说明线程此时已经做好准备,随时等待CPU的调度并不是说 t.start(): 后线程就会立马执行;
运行状态(Running):
当CPU开始调度已经处于就绪状态的线程时,此时线程才真正的开始他的工作,即进入了运行状态。注意(敲黑板!):就绪状态是进入到运行状态的唯一入口。也就是说线程想进入运行状态,那线程就必须先处于就绪状态。
阻塞状态(Blocked):
处于运行状态的线程处于某种原因呢,暂时放弃了对CPU的使用权,停止了执行,此时也就进入了阻塞状态,知道线程再次进入到就绪状态,才有机会被CPU调用进入到运行状态。而根据造成阻塞的原因不同,分为了一下三种阻塞:
-
等待阻塞:运行状态的线程执行到了wate()方法,使线程进入了等待阻塞状态。
-
同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),他就会进入同步阻塞状态。
-
其他阻塞:通过线程的sleep()和join()或发出了I/O请求,线程进入到了阻塞状态。当sleep()超时、join()等待线程终止或超时、I/O处理完毕时,线程就会再次进入就绪状态。
死亡状态(Dead):
线程执行完了或者在执行中因异常退出了run()方法,该线程就走完了他的一生了。
Java多线程的创建和启动
Java线程有三种常见的基本创建方式
继承Thread类,重写其run()方法
实现Runnable接口,并重写实现其run()方法
不必想太多,这个run()方法同样是我们的线程执行体。重写完run方法后创建接口实例,并把该实例作为创建线程的target创建线程。没看懂没关系,直接上代码。
用Callable和Future接口创建线程
具体是创建Callable接口的实现类,并实现call()方法。并使用FutureTask类来包装Callable实现类的对象,且以此FutureTask对象作为Thread对象的target来创建线程。有点绕~直接看代码吧~
这样我们就能清楚的看得出他们之间的关系。发现FutureTask类实际上是同时实现了Runnable和Future接口,使得他有了双重特性了,通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。
原因在于通过ft.get()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ft.get()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。
上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。
线程的开启暂时就讲这么多了,后面的文章还会继续讲述Java线程之如何优雅的关闭线程。
参考: