一、概念
Java中的线程,是以轻量级进程来实现的
其他语言,可以是其他方式来实现,比如go,是协程的方式来实现(用户自己编写程序来实现线程,及线程的调度)
1.进程和线程的关联关系/区别
- 进程包含线程,一个进程至少包含一个线程
- 进程是系统分配资源的最小单位(基本单位),线程是操作系统调度cpu执行的最小单位(基本单位)
- 进程状态的改变会耗费很多时间,线程的效率更高
- 进程占用独立的虚拟地址空间,同一个进程中的多个线程可以共享这个进程的内存。
(1)一个进程要访问另一个的数据,需要使用通信的方式(代价比较大);同一个进程的线程,可以直接使用共享变量 (2)一个进程挂掉不会影响其他进程,但一个进程中的线程挂掉,就可能影响整个进程挂掉(比如一个线程申请的内存太多,超出整个进程的内存,就会挂掉(OOM))
线程和进程的状态: 线程和进程一样,系统也会创建pcb来管理
就绪:线程pcb不在队列的首部 运行:线程pcb处于cpu执行的时间片 状态改变比较耗时: (1)创建 (2)销毁 (3)进入阻塞
线程和进程这些状态改变,都是比较耗时的,只是线程相对进程来说,耗时少一点
Java中,线程以轻量级进程的方式实现,也就具有进程的特征 需要系统调度cpu来执行:
- 并发:一个cpu以时间片轮转调度的方式,依次执行多个线程(人肉眼感知还是“同时”执行)
- 并行:多个cpu在一个时间点,同时执行多个线程
线程到底是就绪态,还是运行态,是操作系统调度决定,程序不知道 Java中,经常说并发编程,其实既包含多线程的并发,也有多线程的并行
二、创建线程
Java中,创建一个线程: 首先,Java程序要运行,必须先有一个main方法的入口类,先执行main方法(这里也会创建一个main线程)
是Java虚拟机创建的线程,然后执行main方法
1.继承Thread类
new Thread:创建一个Java中的线程对象(此时还没有创建系统中的线程(pcb))
2.实现Runnable接口
3.其他变形
3.本质还是继承Thread(匿名内部类) 4.实现Runnable接口(匿名内部类) 5.继承Thread(lambda表达式) 6.实现Runnable(lambda表达式)
4.总结
在我们理解上: new Thread才能创建一个Java中的线程对象,调用start才会创建系统的线程,并申请系统调度执行 Runnable只是一个描述任务的对象,不是线程!
创建线程的方式:
- 继承Thread,重写run方法
- 实现Runnable接口,重写run方法
- 实现Callable接口(之后会补充)
三、多线程的作用/优势:增加运行速度
- 多个线程可以并发并行的执行,提高执行效率
main线程,总共循环20亿次++:
public class 多线程的优势_不使用多线程 {
public static void main(String[] args) {
int num = 10_0000_0000;
long start = System.currentTimeMillis();
for(int i=0;i<2;i++){
for(int j=0;j<num;j++){
}
}
long end = System.currentTimeMillis();
System.out.printf("执行时间:%s\n",end-start);
}
}
两个线程同时并发并行的执行10亿次++:
public class 多线程的优势_使用多线程 {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i=0;i<2;i++){
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<10_0000_0000;j++){
}
}
});
}
while(Thread.activeCount()>1){
Thread.yield();
}
long end = System.currentTimeMillis();
System.out.printf("执行时间:%s\n",end-start);
}
}
每次++次数很大的时候,使用多线程效率高 ++次数少的时候,不使用多线程效率高
多个线程执行任务,任务执行时间越长,相对线程的创建,占用的时间比例就越小,效率就更高 (任务执行时间很快,比如执行一次++,创建的时间就相对更多) 有多个耗时的任务,使用多线程效率更高
四、观察多线程并发并行的特征
两个线程,每个循环10次打印线程名和循环次数
从表现看: 单个线程执行顺序还是代码书写的顺序 多个线程代码之间,执行的顺序,就是并发并行的执行(随机)
public class 多线程并发特性_1 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
for(int i=0;i<10;i++){
try {
Thread.sleep(10);
System.out.printf("线程:%s,执行第 %s 次\n",name,i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName();
for(int i=0;i<10;i++){
try {
Thread.sleep(100);
System.out.printf("线程:%s,执行第 %s 次\n",name,i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"t2");
t1.start();
t2.start();
}
}
执行结果:
五、多线程并发中创建耗时
|