系列文章目录
多线程实现(一)——概念和三种实现多线程实操
多线程实现(二)——线程池实现多线程
多线程实现(三)——JUC异步并发
前言
提示:随着业务场景的并发量逐渐增多,异步编排技术广泛的使用,不得不提多线程,本文就简单介绍多线程的实现方式。
提示:以下是本篇文章正文内容,下面案例可供参考
一、进程?线程?
1.进程本质上是一个程序,是计算机分配资源的基本单位,一个进程至少拥有一个线程。进程与进程之间是隔离的,具有私密性;
2.线程是进程中的一个任务。是cpu分配资源的基本单位。线程之间共享进程资源互相通信
拓展:
问题:1.服务器上运行的进程所需的线程数远大于cpu核心线程数,cpu如何分配资源?
答:cpu通过时间分片的模式,将时间片段轮流分给多个线程。当一个线程时间段耗尽但任务没结束,就会被挂起,等待下一次唤醒。
(类似综艺节目,给每个队的队员固定时间,接力完成任务。)
问题:2.未执行完毕的线程唤醒后如何继续完成任务?(即系统怎么知道线程之前运行到那里?从哪里开始执行)
答:通过寄存器和程序计数器记录执行信息。寄存器存储数据状态信息,程序计数器存储cpu正在执行的指令,执行下一条指令的位置
[为何不合二为一统一存储?一是因为寄存器可读可写,程序计数器只可读,保证了指令的安全不可更改;二是因为缓存,提高效率。
寄存器算出执行指令后存在程序计数器中;三是因为指令共享。当进程多开时,线程的执行指令是相同的,可以做到多对一,节省空间]
问题:3.线程何时分配到时间分片?每个线程分配时间一样多?
答:1)并发模式下通过抢占式调度分配时间分片。即所有线程都会抢占时间分片,获取执行权限。(JVM就是这种)
2)协同式调度:一个线程执行完毕后主动通知系统切换下一个线程。缺点就是正在执行的线程阻塞或者异常了,整个程序就会崩溃。
二、并行?并发
1.并行: 同一时刻,多个线程同时执行,就叫并行执行
2.并发: 一个时间段内,多个线程轮流分配时间分片,抢占式执行,就叫并发。
三、实操多线程
3.1、继承Thread类
代码如下(示例):
public class extendThread {
public static void main(String[] args) {
System.out.println("Thread........start......");
//创建线程对象调用线程
ThreadA threadA = new ThreadA();
//开启线程,主线程先执行,之后才会调用下面的业务方法。(异步)
threadA.start();
System.out.println("Thread........end......");
}
public static class ThreadA extends Thread{
//run 是线程执行主体;多线程业务在run方法中运行
@Override
public void run(){
System.out.println("继承Thread实现方式.....");
//业务代码
int i = 99/3;
System.out.println("业务代码执行结果:" + i + ";"+ this.getName() + ";"+ this.getId());
}
}
}
3.2、实现Runable接口
代码如下(示例):
public class extendThread {
public static void main(String[] args) {
System.out.println("Thread........start......");
//创建线程对象调用线程
ThreadB threadB = new ThreadB();
//调用线程
Thread thread = new Thread(threadB);
//开启线程
thread.start();
System.out.println("Thread........end......");
}
public static class ThreadB implements Runnable{
//run 是线程执行主体;多线程业务在run方法中运行
@Override
public void run(){
System.out.println("实现runnable接口方式.....");
//业务代码
int i = 99/3;
System.out.println("业务代码执行结果:" + i );
}
}
}
3.3、FutureTask实现多线程
代码如下(示例):
public class extendThread {
public static void main(String[] args) {
System.out.println("Thread........start......");
//创建一个实现了callable的对象
ThreadC threadC = new ThreadC();
//创建futureTask对象,把threadC对象传递构造函数中
FutureTask<Integer> task = new FutureTask<Integer>(threadC);
Thread thread = new Thread(task);
//开启线程
thread.start();
//等待子线程执行结束后,获取返回结果
try {
//同步阻塞,必须等到异步线程执行结束后,且返回结果后,在往下执行。
Integer integer = task.get();
System.out.println("拿到的结果是:" + integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//主线程先执行,之后才会调用下面的子线程业务方法。(异步)
System.out.println("Thread........end......");
//3.2简化成匿名内部类 [只要能匿名内部类,就可以使用lambda表达式]
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("实现Callable匿名内部类方式.....");
//业务代码
int i = 99 / 3;
System.out.println("业务代码执行结果:" + i);
return i;
}
};
FutureTask<Integer> task2 = new FutureTask<Integer>(callable);
Thread thread2 = new Thread(task2);
//开启线程
thread2.start();
//3.3lambda方式
FutureTask<Integer> task3 = new FutureTask<Integer>(()->{
System.out.println("用lambda实现FutureTask线程.....");
//业务代码
int i = 99 / 3;
System.out.println("业务代码执行结果:" + i);
return i;
});
Thread thread3 = new Thread(task3);
//开启线程
thread3.start();
}
public static class ThreadC implements Callable<Integer> {
//run 是线程执行主体;多线程业务在run方法中运行
@Override
public Integer call() throws Exception {
System.out.println("实现Callable接口方式.....");
//业务代码
int i = 99/3;
System.out.println("业务代码执行结果:" + i );
return i;
}
}
}