java多线程
相关概念讲解
进程
- 是指一个内存中运行的应用程序,每个进程都有独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位,系统运行一个程序即是一个进程从创建,运行到消亡的过程。
线程
-
进程内部的一个独立执行单元;一个进程可以同时并发的运行多个线程,可以理解为进程便相当于一个单CPU操作系统,而线程便是这个系统中运行的多个任务。
-
windows系统中任务管理器,下图
简单说如果进程是火车的话,那么线程就是火车的每一节车厢
多线程优点
- 不会阻塞用户,因为线程是独立的,可以同时执行多个操作。
- 可以一起执行许多操作,节省时间。
- 线程是独立的,因此如果在单个线程中发生异常,他不会影响其他线程。
并行
- 指两个或两个以上事件在同一时刻发生。
简单说就是你在吃饭的时候,电话响了,你一边打电话,一边吃饭
并发
- 指两个或多个事件在同一时间段内发生。
简单说就是你在吃饭的时候,电话响了,然后你去接电话,电话打完又接着吃饭
多任务处理
- 多任务处理是同时执行多个任务的过程,使用多任务来利用CPU,多任务处理可以通过两种方式实现:
- 基于进程的多任务处理(多进程)
- 基于线程的多任务处理(多线程)
- 基于进程的多任务处理
- 每个进程在内存中都有一个地址,也就是说,每个进程分配一个单独的内存区域。
- 进程是重量级的。
- 进程之间通信的成本很高。
- 从一个进程切换到另一个进程需要一些时间来保存和加载寄存器,内存映射,更新列表等。
- 基于线程的多任务处理
- 线程共享相同的地址空间。
- 线程是轻量级的。
- 线程之间通信成本很低。
- 一次只能执行一个线程。
线程的生命周期(线程状态)
- 线程的生命周期,线程的生命周期由JVM控制。
- **初始(New):新创建一个线程对象,但还没有调用start()**方法。
- 运行(Runnable):java线程中将就绪(ready)和运行中(running)两种状态统称为“运行”。线程对象创建后,其他线程(如main线程)调用该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间后变为运行中状态(running)。
- **阻塞(Blocked)?*表示线程阻塞于锁。
- **等待(Waiting)?*进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(Timed_Waiting):该状态不同于Waiting,它可以在指定的时间后自行返回。
- **终止(Terminated)?*表示该线程已经执行完毕。
线程状态
- 新建(new):如果创建Thread类的实例但在调用**start()**方法前,线程处于新建(new)状态。
- 就绪(Runnable):调用start()方法后,线程处于runnable状态,但线程调度程序尚未选择它作为正在运行的线程。
- **运行(Running):**如果线程调度程序已选择它,则线程处于运行状态.
- **阻塞(Blocked)?*这时线程仍处于活动状态但当前没有资格运行的状态。
- **终止(Terminated):当run()**方法退出时,线程处于终止或死亡状态。
线程创建方式
- 创建线程的方式有
- 通过继承Thread类
- 通过实现Runnable接口
Thread类简单介绍
- Thread类提供了在线程上创建和执行操作的构造函数和方法,Thread类扩展了Object类并实现了Runnable接口。
常用的Thread类构造函数
Thread()
Thread(String name)
Thread(Runnable r)
Thread(Runnable r,String name)
常用方法
方法名 | 概述 |
---|---|
public void run() | 用于执行线程的操作 |
public void start() | 开始执行线程,JVM调用线程上的run()方法 |
public void sleep(long miliseconds) | 按指定的毫秒数等待线程死亡 |
public void join() | 等待线程死亡 |
public void join(long miliseconds) | 按指定的毫秒数等待线程死亡 |
public void getPriority() | 返回线程的优先级 |
public void setPriority(int priority) | 更改线程的优先级 |
public void stop() | 用于停止线程(deprivated) |
代码演示
public class Thread1 extends Thread {
@Override
public void run() {
System.out.println("线程启动");
}
public static void main(String[] args) {
Thread1 th = new Thread1();
Thread t = new Thread();
t.start();
}
}
- 控制台输出
- join方法简单演示
/**
* @program: Bridge Pattern
* @description:join()无参方法测试
* @author: Mr.Yan
* @create: 2019-03-21 20:53
**/
public class JoinDemo1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(i + " ");
}
}
public static void main(String[] args) {
JoinDemo1 dj1 = new JoinDemo1();
JoinDemo1 dj2 = new JoinDemo1();
JoinDemo1 dj3 = new JoinDemo1();
dj1.start();
try {
dj1.join();
}catch (Exception e) {
System.out.println(e);
}
dj2.start();
dj3.start();
}
}
- 控制台输出
0 1 2 3 4 5 6 7 8 9 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
- 我们可以看到当dj1执行完毕之后,dj2和dj3才开始执行
- join(long miliseconds)方法简单演示
public class JoinDemo2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
public static void main(String[] args) {
JoinDemo2 jd1 = new JoinDemo2();
JoinDemo2 jd2 = new JoinDemo2();
JoinDemo2 jd3 = new JoinDemo2();
jd1.start();
try {
jd1.join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
jd2.start();
jd3.start();
}
}
- 查看控制台发现,当jd1完成其任务2000毫秒后,jd2和jd3才开始执行
Runnable接口简单介绍
-
Runnable接口由任何其实例由线程执行类实现,Runnable接口只有一个**run()**方法。
-
public void run(); //用于执行线程的操作
代码演示
public class Thread1 implements Runnable {
@Override
public void run() {
System.out.println("线程启动");
}
public static void main(String[] args) {
Thread1 th = new Thread1();
Thread t = new Thread(th);
t.start();
}
}
- 控制台输出
Thread 与 Runnable区别
- 使用继承的话,不适合资源共享,实现接口,容易实现资源共享。
- java是单继承,多实现的。
Thread类中的start() 与 run() 方法的区别
- **start()**方法用来启动新创建的线程。
- **run()**方法只会在原来线程中调用,没有新线程的启动。