0.概要
进程:
每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)
线程:
同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
注:线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。
1.多线程
1.多进程是指操作系统能同时运行多个任务(程序)
2.多线程是指在同一程序中有多个顺序流在执行
3.多个线程交替占用CPU资源,而非真正的并行执行
多线程的好处
1.充分利用CPU的资源
2.简化编程模型
3.良好的用户体验
并行执行
通常表示同一个时刻有多条指令代码在处理器上同时运行
往往需要的哟个处理器支持
并发运行
表示在一个处理器中,操作系统为了提高程序的运行效率,将CPU的执行时间分成多个时间片,分配给同一进程的不同线程
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口
2.java.lang.Thread类
比较常用的一种,如果说你只是想起一条线程。没有什么其它特殊的要求,那么可以使用Thread
方法 | 描述 | 类型 |
Thread() | 创建Thread对象 | 构造方法 |
Thread(Runnable target) | 创建Thread对象,target为run()方法被调用的对象 | 构造方法 |
Thread(Runnable target,String name) | 创建Thread对象,target为run()方法被调用的对象, name为新线程的名称 | 构造方法 |
void run() | 执行任务操作的方法 | 实例方法 |
void start() | 使该线程开始执行,JVM将调用该线程的run()方法 | 实例方法 |
void sleep(long milis) | 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行) | 静态方法 |
Thread currentThread() | 返回当前线程对象的引用 | 静态方法 |
3.实现java.lang.Runnable接口
也是非常常见的一种,我们只需要重写run方法即可
1.Runnable接口位于java.lang包
2.只提供一个抽象方法run()的声明
实现步骤
1.定义MyRunnable类实现Runnable接口
2.实现run()方法,编写线程执行体
3.创建线程对象,调用start()方法启动线程
4.Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享
实现Runnable接口比继承Thread类所具有的优势:
1.适合多个相同的程序代码的线程去处理同一个资源
2.可以避免java中的单继承的限制
3.增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4.线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
5.线程状态
1.新建状态:新创建了一个线程对象
2.就绪状态:线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权
3、运行状态:就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态:阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态,阻塞的情况分三种。
1、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)
2、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
3、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态:线程执行完了或者因异常退出了run()方法,该线程结束生命周期
6.主线程
Java程序启动时,一个线程立即随之启动,通常称之为程序的主线程
- main()方法即为主线程入口
- 产生其他子线程的线程
- 必须最后完成执行,因为它执行各种关闭动作
7.线程的创建和启动
Java中创建线程的两种方式:
1.继承java.lang.Thread类
2.实现java.lang.Runnable
使用线程的步骤
8.继承Thread类创建线程
1.自定义线程类继承自Thread类
2.重写run()方法,编写线程执行体
3.创建线程对象,调用start()方法启动线程
9.线程休眠
1.sleep(long millis): 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
2.yield():暂停当前正在执行的线程对象,并执行其他线程。
sleep()和yield()的不同点:
-
sleep()方法会给其他线程运行机会,不考虑其他线程的优先级,因此较低优先级线程可能会获得运行机会
-
yield()方法只会将运行机会让给相同优先级或者更高优先级的线程
-
调用sleep()方法需处理InterruptedException异常,而调用yield()方法无此要求
sleep()和yield()的相同点:
-
Thread类的静态方法
- 会使但付钱处于运行状态的线程放弃CPU使用权,将运行机会让给去其他线程
10.run方法与start方法区别
run:只有主线程一条执行路径
start:多条执行路径,主线程和子线程并行交替执行
11.线程优先级
线程优先级由1~10表示,1最低,默认优先级为5
优先级高的线程获得CPU资源的概率较大
12.线程调度
- 线程运行完毕
- 有比当前线程优先级更高的线程抢占了CPU
- 线程休眠
- 线程因等待某个资源而处于阻塞状态
- 指按照特定机制为多个线程分配CPU的使用权
- 每个线程执行时都具有一定的优先级
常用的线程操作方法
方法 | 说明 |
int getPriority() | 返回线程的优先级 |
void setPrority(int newPriority) | 更改线程的优先级 |
boolean isAlive() | 测试线程是否处于活动状态 |
void join() | 进程中的其他线程必须等待该线程终止后才能执行 |
void interrupt() | 中断进程 |
void yieId() | 暂停当前正在执行的线程对象,并执行其他线程 |
13.线程同步的特征
1.不同的线程在执行以同一个对象所谓锁标记的同步代码块或通过不方法时,因为要获得这个对象的锁而相互牵制
2.多个并发线程访问同一资源的同步代码或同步方法时:
(1)同一时刻只能有一个线程进入synchronized(this)同步代码块
(2)当一个线程访问一个synchronized(this)同步代码块时,其他synchronized(this)同步代码块同样被锁定
(3)当一个线程访问一个sunchronized(this)同步代码块,其他线程可以访问该资源的非syhchronized(this)同步代码
3.如果多个线程访问的不是同一共享资源,无需同步
提示:使用同步代码块和同步方法完成线程同步,二者的实现结果没有区别
不同点:
1.同步方法便于阅读理解
2.同步代码块更精确地限制访问区域,会更高效