首页 > 代码库 > 那些年搞不懂的多线程、同步异步及阻塞和非阻塞(一)---多线程简介

那些年搞不懂的多线程、同步异步及阻塞和非阻塞(一)---多线程简介

1、进程和线程的概念

进程:运行中的应用程序称为进程,拥有系统资源(cpu、内存)

线程:进程中的一段代码,一个进程中可以有多段代码。本身不拥有资源(共享所在进程的资源);

在java中,程序入口被自动创建为主线程,在主线程中可以创建多个子线程。

区别:

 1、是否占有资源问题

 2、创建或撤销一个进程所需要的开销比创建或撤销一个线程所需要的开销大。

 3、进程为重量级组件,线程为轻量级组件

 

多进程: 在操作系统中能同时运行多个任务(程序)

多线程: 在同一应用程序中有多个功能流同时执行

 

已经有了进程,为什么还会需要线程呢?主要原因如下:

  1. 许多应用程序中,同时发生着多个活动。将这些应用程序分解成多个准并行的线程,程序设计的模型会变成更加简单。
  2. 由于线程比进程进行更加轻量,创建和取消更加容易。
  3. 如果程序是IO密集型,那么多线程执行能够加快程序的执行速度。(如果是CPU密集型,则没有这个优势)
  4. 在多CPU系统中,多线程是可以真正并行执行的。

 

2、线程的主要特点

①、不能以一个文件名的方式独立存在在磁盘中;

②、不能单独执行,只有在进程启动后才可启动;

③、线程可以共享进程相同的内存(代码与数据)。

 

3、多线程原理

同一时间,CPU只能处理1条线程,只有1条线程在工作(执行)
多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)
如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象

思考:如果线程非常非常多,会发生什么情况?

CPU会在N多线程之间调度,CPU会累死,消耗大量的CPU资源

每条线程被调度执行的频次会降低(线程的执行效率降低)

 

4、线程的主要用途

①、利用它可以完成重复性的工作(如实现动画、声音等的播放)。

②、从事一次性较费时的初始化工作(如网络连接、声音数据文件的加载)。

③、并发执行的运行效果(一个进程多个线程)以实现更复杂的功能

 

5、多线程(多个线程同时运行)程序的优缺点

优点:

①、可以减轻系统性能方面的瓶颈,因为可以并行操作;

②、提高CPU的处理器的效率,在多线程中,通过优先级管理,可以使重要的程序优先操作,提高了任务管理的灵活性;

另一方面,在多CPU系统中,可以把不同的线程在不同的CPU中执行,真正做到同时处理多任务。

缺点:

1、开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能

2、线程越多,CPU在调度线程上的开销就越大

3、程序设计更加复杂:比如线程之间的通信、多线程的数据共享

 

6、多线程的生命周期

线程状态:

与人有生老病死一样,线程也同样要经历新建、就绪、运行(活动)、阻塞和死亡五种不同的状态。这五种状态都可以通过Thread类中的方法进行控制。

 

创建并运行线程:

① 新建状态(New Thread):在Java语言中使用new 操作符创建一个线程后,该线程仅仅是一个空对象,它具备类线程的一些特征,但此时系统没有为其分配资源,这时的线程处于创建状态。

线程处于创建状态时,可通过Thread类的方法来设置各种属性,如线程的优先级(setPriority)、线程名(setName)和线程的类型(setDaemon)等。

② 就绪状态(Runnable):使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,使该线程处于就绪状态。此外,如果某个线程执行了yield()方法,那么该线程会被暂时剥夺CPU资源,重新进入就绪状态。

③ 运行状态(Running):Java运行系统通过调度选中一个处于就绪状态的线程,使其占有CPU并转为运行状态。此时,系统真正执行线程的run()方法。

a)     可以通过Thread类的isAlive方法来判断线程是否处于就绪/运行状态:当线程处于就绪/运行状态时,isAlive返回true,当isAlive返回false时,可能线程处于阻塞状态,也可能处于停止状态。

④ 阻塞和唤醒线程

阻塞状态(Blocked):一个正在运行的线程因某些原因不能继续运行时,就进入阻塞 状态。这些原因包括:

  • 等待阻塞:当线程执行了某个对象的wait()方法时,线程会被置入该对象的等待集中,直到执行了该对象的notify()方法wait()/notify()方法的执行要求线程首先获得该对象的锁。
  • 同步阻塞:当多个线程试图进入某个同步区域(同步锁)时,没能进入该同步区域(同步锁)的线程会被置入锁定集(锁池)中,直到获得该同步区域的锁,进入就绪状态。
  • 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

⑤ 死亡状态(Dead):线程在run()方法执行结束后进入死亡状态。此外,如果线程执行了interrupt()或stop()方法,那么它也会以异常退出的方式进入死亡状态。

 

7、终止线程的三种方法

① 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止,推荐使用。

② 使用stop方法强制终止线程(这个方法不推荐使用,因为stop和suppend、resume一样,也可能发生不可预料的结果)。

③ 使用interrupt方法中断线程。

 

那些年搞不懂的多线程、同步异步及阻塞和非阻塞(一)---多线程简介