课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
我们在上文中给大家简单分析了关于多任务环境下的线程之间的通信问题,而今天我们就再来了解一下关于java开发线程的一些基本知识点。
1. 关于并发
虽然编程问题中相当大的一部分都可以通过使用顺序编程来解决,但是由于cpu的运算速度比计算机系统中存储及通信等子系统的速度要快几个量级,相对而言在计算过程中,大部分时间会花费在磁盘I/O、网络通信上面,这样处理器在大部分时间里面就都需要等待其他资源,为了不浪费处理器的强大计算能力,让计算机“同时”处理几项任务则是简单而有效的一个“压榨”手段。
除了充分利用cpu的计算能力,在后端开发中,服务端往往也需要同时对多个客户端提供服务,这是一个更具体的并发应用场景。衡量一个服务性能的好坏,每秒事物处理数(Transactions Per Second,TPS)是一个重要指标,代表着一秒内服务端平均能响应的请求总数,而TPS值与程序的并发能力又有非常密切的关系,程序并发协调得越有条不紊,效率自然越高;反之,线程之间频繁阻塞甚至死锁,则会大大降低程序的并发能力。
Java支持多线程编程,而且服务端是其擅长的领域之一,不过对于如何写好并发应用程序却又是服务端开发的难点之一。学习并发编程就像进入了一个全新的领域,如果你花点儿工夫,就能明白其基本机制,但要想真正地掌握它的实质,就需要深入的学习和理解。
说到并发,需要和并行进行区别:
所谓并发,其实是按顺序执行的,cpu在任一时间只执行一个线程,通过给不同线程分配时间段的形式来进行调度,只是看起来好像多个任务是同时执行的;
并行,就是多个任务同时在进行着的;
2. 基本线程机制
并发编程使我们可以将程序划分为多个分离的、独立运行的任务。通过使用多线程机制,这些独立任务(也被称为子任务)中的每一个都将通过执行线程来驱动。一个线程就是在进程中的一个单一的顺序控制流,单个进程可以拥有多个并发执行的任务。
线程模型为编程带来了便利,它简化了在单一程序中同时交织在一起的多个操作的处理。在使用线程时,CPU将轮流给每个任务分配其占用的时间。每个任务都觉得自己在一直占用CPU,但事实上CPU时间是划分成片段分配给了所有的任务(例外情况是程序确实运行在多个CPU之上)。线程的一大好处是可以使你从这个层次抽身出来,即代码不必知道它是运行在具有一个还是多个CPU的机器上,所以,使用线程机制是一种建立透明的、可扩展的程序的方法。多任务和多线程往往是使用多处理器系统的合理方式。
在JDK1.2之后,Java中的线程模型是基于操作系统原生线程模型来实现,但这和Java程序的编码来说是没有影响的。因为Java语言提供了在不同硬件和操作系统平台下对线程操作的统一处理,每个已经执行start()且还未结束的java.lang.Thread类的实例就代表了一个线程。
我们可以通过三种传统的方式来通过线程驱动任务:
new一个Thread类,并重写run方法(也可以通过匿名类的方式);
实现Runnable接口,传入Thread的构造器中;
直接在main函数中new一个实现了Runnable接口的类,实例化,直接调用其run方法,其实是由main线程来驱动的;
3. 线程状态
Java语言定义了5种线程状态,在任一时间点,一个线程只能有且只有其中的一种状态,分别是新建、运行、等待、阻塞、结束。
3.1 新建(New)
创建后尚未启动的线程就处于这种状态。
3.2 运行(Runable)
Runable包括了操作系统线程状态中的 Running和 Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着CPU为它分配执行时间。
3.3 无限期等待(Waiting)
处于这种状态的线程不会被分配CPU执行时间,它们要等待被其他线程显式地唤醒。以下方法会让线程陷入无限期的等待状态:
没有设置 Timeout参数的Object.wait()方法;
没有设置 Timeout参数的Thread.join()方法;
LockSupport park()方法;
3.4 有限期等待(Timed Waiting)
处于这种状态的线程也不会被分配CPU执行时间,不过无须等待被其他线程显式地唤醒,在一定时间之后它们会由系统自动唤醒。以下方法会让线程进入限期等待状态:
Thread.sleep()方法;
设置了Timeout参数的Object.wait()方法;
设置了Timeout参数的Thread.join()方法;
LockSupport.parkNanos()方法;
LockSupport.parkUntil()方法;
3.5 阻塞(Blocked)
线程被阻塞了,“阻塞状态”在等待着获取到一个排他锁(synchronized中获取的monitor),这个事件将在另外一个线程放弃这个锁的时候发生,在程序等待进入同步区域的时候,线程将进入这种状态。
3.6 结束(Terminated)
已终止线程的线程状态,线程已经结束执行。
4. 线程常用方法
在线程运行的过程中,我们需要通过各种方式来操纵线程(比如暂停,中断线程)或者协调多个线程(比如通知别的线程)。常用的方式有sleep、join、yield、wait、notify/notifyAll。
4.1 休眠(sleep)
调用某个线程的sleep()方法可以使其休眠给定的时间。
sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据。而join()方法会释放"锁标志"。
4.2 加入一个线程(join)
一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到另一个线程结束才继续执行。如果线程A在另一个线程B上调用B.join(),则线程A将被挂起,直到目标线程B结束才恢复(即B.isAlive()返回为假)。
也可以在调用join()时带上一个超时参数(单位可以是毫秒,或者毫秒和纳秒),这样如果目标线程在这段时间到期时还没有结束的话, join方法总能返回。对join()方法的调用可以被中断,做法是在调用线程上调用interrupt方法,这时需要用到try- -catch子句,与sleep类似。
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。