首先,我们需要了解一些基本知识:
微观概念:
并行: 指两个或多个事件在同一时刻点发生
并发: 指两个或多个事件在同一时间段内发生
一、进程(Process)与线程(thread)
进程: 运行的应用程序和所占用的资源,是指一个内存中运行的应用程序。每个进程都有自己独立的一个内存空间(数据交互困难),一个应用程序可以同时启动多个进程。比如同时听音乐和看小说
线程:进程中单个任务执行流,是指进程中的一个执行任务(控制单元),一个进程可以同时并发运行多个线程。多任务系统,该系统可以运行多个进程,一个进程可以 执行多个任务,一个进程包含多个线程
多线程:一个进程至少有一个线程,为了提高效率,可以在一个进程中开启多个执行任务,即多线程
注意:因为一个进程中的多线程是并发进行的,那么从微观角度上来考虑也是有先后顺序的,那么哪个线程
先执行完全取决于CPU调度器(java线程一般取决于JVM),程序员控制不了
二、多线程的优势
- 进程之间不能共享内存,而线程之间共享内存(堆内存)
- 系统创建进程时需要为该进程重新分配系统资源,创建线程则代价小很多,因此实现多任务并发时,多线程效率更高
- Java语言本身内置多线程功能的支持,而不是单纯作为底层系统的调度方式,从而简化了多线程编程
- 多线程下载(网络带宽) 即一个线程就是一个文件的下载通道,多线程就是同时开启了多个下载通道(bit位 byte字节 1024kb/s -> 1024/8 128比如 单行道与多行道 LOL CS)
三、创建和启动线程 【重点】
方式一:继承Thread类
步骤:
- 定义一个类继承Thread类
- 在该类中覆盖Thread类中的run方法
- 在run方法中实现需要执行的操作(注明线程执行体)
- 在main方法(线程)中,创建线程对象,并调用start()方法启动线程(A类 a = new A类();a.start(); 或者 Thread t = new Thread(new A类());t.start() )
eg:
package com.javaweb.practice;
public class MyThread extends Thread{
public MyThread(String name){
super(name); //引用Thread的构造方法为Thread取名
}
public void run(){
for(int i=0 ; i<10 ; i++){
System.out.println(getName()+":正在执行!"+i);
}
}
}
package com.javaweb.practice;
import java.util.Date;
public class Test extends Date {
public static void main(String[] args) {
MyThread mt = new MyThread("新的线程");
mt.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程!"+i);
}
}
}
结果:
main线程!0
main线程!1
main线程!2
main线程!3
main线程!4
main线程!5
main线程!6
main线程!7
新的线程:正在执行!0
新的线程:正在执行!1
新的线程:正在执行!2
新的线程:正在执行!3
新的线程:正在执行!4
新的线程:正在执行!5
新的线程:正在执行!6
新的线程:正在执行!7
新的线程:正在执行!8
新的线程:正在执行!9
main线程!8
main线程!9
注意:千万不要使用对象调用run方法,如果调用run方法,等于就是只启动了一个线程,未开启别的线程
方法:
- getName(): 拿到当前线程的名称
- setName(String name): 给当前线程的名字赋值
- currentThread() 返回对当前正在执行的线程对象的引用。
- sleep() 当前线程睡眠,让其他线程抢CPU资源
方式二:实现Runnable接口(仅作为一个线程任务丢给线程去处理)
步骤:
- 定义一个类A实现Runable接口,注意A类不是线程类
- 在A类中覆盖Runable接口中的run方法
- 在run方法中实现需要执行的操作(注明线程执行体)
- 在main方法(线程)中,创建线程对象,并调用start()方法启动线程(Thread t = new Thread(new A());t.start();)
eg:
package com.javaweb.practice;
import java.util.Currency;
public class MyRunnable implements Runnable {
public void run() {
for(int i=0 ; i<10 ; i++){
System.out.println("线程"+i);
}
}
}
package com.javaweb.practice;
public class Test {
public static void main(String[] args) {
//创建线程执行目标类对象
MyRunnable runn = new MyRunnable();
//将Runnable接口的子类对象作为参数传递给Thread类的构造函数
Thread thread01 = new Thread(runn,"线程1");
Thread thread02 = new Thread(runn,"线程2");
//开启线程
thread01.start();
thread02.start();
for (int i = 0; i < 10; i++) {
System.out.println("main线程!"+i);
}
}
}
四 继承方式与实现方式的区别:
继承方式:
- java中类是单继承的,如果继承了Thread,该类就不能再有其他直接父类了
- 从操作上来分析,继承方式更简单,获取线程的名称也简单
- 从多线程共享同一个资源上分析,继承方式不能做到
实现方式(推荐使用):
- java中的类可以实现多个接口,此类还可以继承其他的类
- 操作上实现方式稍微复杂点,获取名称只能通过Thread.currentThread().getName()来拿
- 从多线程共享一个资源上,实现方式才能做到是否共享同一个资源
五、线程的生命周期
1. 新建 : new thread实例对象
2. 就绪 : 调用start() 启动线程进入就绪
3. 运行 :运行run方法里面的代码
4. 中断(阻塞):正在运行的线程由于外部原因引起当前线程中断或阻塞,等到引起阻塞原因消失,回到就绪状态
5.死亡 : 中断线程