目录
一、为什么要有多线程
二、名词解释
1、进程和线程
2、并发和并行
3、总结
三、创建线程
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口
4、线程池创建线程
四、线程状态
五、守护线程和线程优先级
随着计算机的发展,单核的CPU发展到多核的CPU,CPU的性能越来越高,为了充分发挥CPU的计算性能和提高CPU硬件资源的利用率于是在进程的基础上演变出了多线程。使用多线程可以提高程序效率,快速响应给客户端,给用户更加好的体验,每个线程之间并行执行互不影响。
进程:进程是一个具有独立功能的程序(例如 QQ、微信、酷狗等应用),进程是系统进行资源分配和调度的一个独立单位。那么什么是java程序的进程呢?Java编写的程序都运行在Java虚拟机(JVM)中,每当使用Java命令启动一个Java应用程序时,就会启动一个JVM进程,这个应用就是一个JAVA进程。
线程:线程是进程的一个实体,是指“进程代码段”的一次顺序执行流程。线程是CPU调度的最小单位。一个进程可以有一个或者多个线程(例如 QQ是一个进程,发消息是一个线程,视频也是一个线程),各个线程之间共享进程的内存空间、系统资源,进程是操作系统资源分配的最小单位。
串行:一次只能执行一个任务,并且这个任务执行完之后才能执行下一个任务。
并行:当系统有一个以上CPU时,则线程的操做有可能非并发.当一个CPU执行一个线程时,另外一个CPU能够执行另外一个线程,两个线程互不抢占CPU资源,能够同时进行,这种方式称为并行。
注:进程也可以并行执行。
并发:并发是一种现象,同时运行多个程序或多个任务需要被处理的现象。这些任务可能是并行执行的,也可能是串行执行的,和CPU核心数无关,是操作系统进程调度和CPU上下文切换达到的结果。、
注:当有多个线程在运行时,若是系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间片段,再将时间片段分配给各个线程执行,由于CPU切换特别快对我们来说就像是并行执行,实际是线程之间在交替执行。
进程和线程的区别
并发和并行的区别
并发和并行是两个相似但又有区别的概念。它们都可以表示两个或者多个任务一起执行,但是侧重点有所不同。并发偏向于多个任务交替执行,而多个任务之间还可以是串行的。而并行就是指同时执行。
package com.xiaojie.juc.thread.mytest;
/**
* @author xiaojie
* @version 1.0
* @description: 继承的方式创建线程
* @date 2021/12/11 22:34
*/
public class ExtendsDemo{
public static void main(String[] args) {
System.out.println("主线程执行,线程名称是:" + Thread.currentThread().getName());
new MyThread().start();
}
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("子线程执行,线程名称是:" + Thread.currentThread().getName());
}
}
}
/**
* @author xiaojie
* @version 1.0
* @description: 实现 Runnable
* @date 2021/12/11 22:39
*/
public class RunableDemo {
public static void main(String[] args) {
System.out.println("主线程执行,线程名称是:" + Thread.currentThread().getName());
// MyThread myThread = new MyThread();
// Thread thread=new Thread(myThread);
// thread.start();
//或者 下面这种写法
Thread thread1 = new Thread(() -> {
System.out.println("子线程执行,线程名称是:" + Thread.currentThread().getName());
});
thread1.start();
}
static class MyThread implements Runnable {
@Override
public void run() {
System.out.println("子线程执行,线程名称是:" + Thread.currentThread().getName());
}
}
}
package com.xiaojie.juc.thread.mytest;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author xiaojie
* @version 1.0
* @description: 实现Callable接口
* @date 2021/12/11 22:48
*/
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread myThread = new MyThread();
FutureTask futureTask = new FutureTask(myThread);
new Thread(futureTask).start();
//获取执行结果
System.out.println(futureTask.get());
}
static class MyThread implements Callable {
//这种方式是获取现场执行结果,有返回值
@Override
public String call() throws Exception {
return "实现Callable接口的方式创建线程。。。。。。";
}
}
}
/**
* @author xiaojie
* @version 1.0
* @description: 基于线程池创建线程
* 有4中线程池,以后总结。
* @date 2021/12/11 22:55
*/
public class ExecutorsDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> System.out.println("基于线程池创建线程,线程名称为"+Thread.currentThread().getName()));
}
}
public enum State {
NEW, //新建
RUNNABLE,//运行状态 包含正在运行和就绪俩种状态
BLOCKED,//阻塞状态
WAITING,//等待状态
TIMED_WAITING,//限时等待
TERMINATED;//终止状态
}
1、在调用start()方法之后进入就绪状态,等待线程获取CPU时间片。
2、当线程获取到CPU的时间片时开始执行。
3、当CPU时间片用完之后就会再次进入就绪状态。
4、如果线程执行遇到synchronized关键字或者调用wait()、sleep()、join()等方法就会进入阻塞状态。
5、wait()方法遇到notify()或者notifuAll();join()等目标现成执行完毕等就会重新进入就绪状态。
6、当线程执行完毕,或者线程的run()方法发生异常,都会使线程进入终止状态
注意:
守护线程
守护线程是进程运行时提供的某种后台服务的线程,比如GC线程。当用户线程都执行结束时,守护线程也会自动退出。守护线程需要在线程启动之前设置为守护线程
thread.setDaemon(true);
使用守护线程注意点:
1、守护线程必须在线程启动前设置。
2、守护线程存在被虚拟机强制终止的风险,所以守护线程中尽量不去访问系统资源,如文件句柄、数据库库连接。
3、守护线程创建的线程也是守护线程,如果显示调用thread.setDaemon(false),则新的线程可以调整为用户线程。
线程优先级
线程的调度方式是基于CPU的时间片方式进行线程调度。线程的调度模型主要有两种
public static void main(String[] args) {
System.out.println("主线程执行,线程名称是:" + Thread.currentThread().getName());
MyThread myThread1 = new MyThread();
myThread1.setName("thread1----");
myThread1.setPriority(10);
MyThread myThread2 = new MyThread();
myThread2.setName("thread2----");
myThread2.setPriority(3);
MyThread myThread3 = new MyThread();
myThread3.setName("thread3----");
myThread3.setPriority(1);
myThread3.start();
myThread2.start();
myThread1.start();
}
运行结果如下图
注意:
1、线程的优先级最大是10,最小是1,超过这个范围就会报java.lang.IllegalArgumentException异常。
2、由图可见线程3执行优先于线程2。并不是说线程优先级高就一定先执行,而是优先级的高的线程更容易获取到CPU的时间片,先执行的机会就越多。
参考:
https://www.pdai.tech/md/java/thread/java-thread-x-theorty.html
《JAVA高并发核心编程(卷2):多线程、锁、JMM、JUC、高并发设计》-尼恩编著
《JAVA高并发程序设计》-葛一鸣著