多线程入门
1 多线程相关的概念
- 并发与并行
- 并行:在同一时刻,有多个任务在多个CPU上同时执行。
- 并发:在同一时刻,有多个任务在单个CPU上交替执行。
- 进程与线程
- 进程:就是操作系统中正在运行的一个应用程序。
- 线程:就是应用程序中做的事情。比如:360软件中的杀毒,扫描木马,清理垃圾。
2 什么是多线程
- 是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。
- 好处 : 提高任务的执行性能
3 多线程的创建方式
3.1 继承Thread方式
- 基本步骤:
- 创建一个类继承Thread类。
- 在类中重写run方法(线程执行的任务放在这里)
- 创建线程对象,调用线程的start方法开启线程。
- 执行程序,观察控制台的打印数据的现象
package com.zqc.thread_demo;
/**
* 线程的创建方式1:继承Thread方式
*
* 基本步骤 :
* 1 创建一个类继承Thread类。
* 2 在类中重写run方法(线程执行的任务放在这里)
* 3 创建线程对象,调用线程的start方法开启线程。
*
*/
public class MyThreadDemo01 {
public static void main(String[] args) {
//2.创建线程对象,调用线程的start方法开启线程。
MyThread mt = new MyThread();
// void setName(String name):将此线程的名称更改为等于参数 name
// mt.setName("线程1");
//3.开启线程
mt.start();
//mt.run();
//main线程:打印1到100的数字
for (int i = 1; i <= 100; i++) {
// Thread.currentThread() : 获取当前线程的对象
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
//1.创建一个类继承Thread类。
class MyThread extends Thread {
//重写run方法(线程执行的任务放在这里)
@Override
public void run() {
//新线程:打印1到100的数字
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + ":" +i);
}
}
}
3.2 实现Runable方式
- 构造方法
- public Thread(Runnable target)
- public Thread(Runnalbe target , String name)
- 实现步骤
- 定义任务类实现Runnable,并重写run方法
- 创建任务对象
- 使用含有Runnable参数的构造方法,创建线程对象并指定任务。
- 调用线程的start方法,开启线程
package com.zqc.thread_demo;
/**
* 线程的创建方式2 :实现Runnable方式
* Thread类
* public Thread(Runnable target) : 接受一个Runnable接口的实现类对象
* public Thread(Runnable target , String name) :
* 第一个参数 : 接受一个Runnable接口的实现类对象
* 第二个参数 : 给线程设置名字
*/
public class MyThread02 {
public static void main(String[] args) {
// 2 创建任务对象
MyRunnable mr = new MyRunnable();
// 4 创建Thread类型的对象 , Thread类的构造方法需要接受一个Runnable实现类对象
Thread t = new Thread(mr , "线程1");
// 5 调用线程的start方法,开启线程
t.start();
// main : 打印1到100的数字
for (int i = 1; i <= 100; i++) {
// Thread.currentThread() : 获取当前线程的对象 (Thread类的对象)
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
//1.定义任务类实现Runnable,并重写run方法
class MyRunnable implements Runnable {
@Override
public void run() {
//打印1到100的数字
for (int i = 1; i <= 100; i++) {
// Thread.currentThread() : 获取当前线程的对象 (Thread类的对象)
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
3.3 实现Runable方式
实现步骤
- 定义一个类 实现 Callable接口
- 重写Callable接口中的抽象call方法
- 创建Callable的实现类对象
- 创建FutureTask类的对象 , 让Callable实现类对象作为构造参数
- 创建Thread类的对象 , 让FutureTask作为构造参数
- 开启线程
- 获取线程执行完毕之后返回的结果
package com.zqc.thread_demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* 实现线程的第三种方式 : 实现Callable接口
*/
public class MyThread03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 3 创建Callable的实现类对象
MyCallable myCallable = new MyCallable();
// 4 创建FutureTask类的对象 , 让Callable实现类对象作为构造参数
// public FutureTask(Callable<V> callable)
FutureTask<String> task = new FutureTask<>(myCallable);
// 5 创建Thread类的对象 , 让FutureTask作为构造参数
Thread t = new Thread(task);
// 开启线程
t.start();
// System.out.println(1);
// 获取线程执行完毕之后返回的结果
String result = task.get();// 具备阻塞作用
// System.out.println(2);
System.out.println(result);
}
}
//1 定义一个类 实现 Callable接口
class MyCallable implements Callable<String> {
// 2 重写Callable接口中的抽象call方法
@Override
public String call() throws Exception {
for (int i = 1; i <= 999; i++) {
System.out.println("送给女孩的第" + i + "朵玫瑰");
}
return "答应了...";
}
}
4 Thread类中常用方法
- String getName():返回此线程的名称
- Thread类中设置线程的名字
- void setName(String name):将此线程的名称更改为等于参数 name
- 通过构造方法也可以设置线程名称
- public static Thread currentThread():返回对当前正在执行的线程对象的引用
- public static void sleep(long time):让线程休眠指定的时间,单位为毫秒
- public void join() : 具备阻塞作用 , 等待这个线程死亡,才会执行其他线程
- 线程有两种调度模型
- 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程
- 获取的 CPU 时间片相对多一些