概念
进程
进程是程序的基本执行实体
线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
多个线程组成了多线程
多线程应用场景
- 软件中的耗时操作
- 拷贝、迁移大文件
- 加载大量的资源文件
想让多个事情同时运行就需要多线程
并发和并行
并发
在同一时刻,有多个指令在单个CPU上交替执行
并行
在同一时刻,有多个指令在多个CPU上同时执行
多线程实现方式
继承Thread类
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Hello World");
}
}
}
实现Runnable接口的方式进行实现
public class ThreadDemo02 {
public static void main(String[] args) {
Myrun mr = new Myrun();
Thread t1 = new Thread(mr);
t1.start();
}
}
public class Myrun implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("Hello World");
}
}
}
利用Callable接口和Future接口方式实
特点:可以获取到多线程运行结果
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo03 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建MyCallahle对象
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread t1 = new Thread(ft);
t1.start();
Integer result = ft.get();
System.out.println(result);
}
}
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
return sum;
}
}
多线程三种实现方式对比
常见的成员方法
设置以及获取线程的优先级
默认优先级为5,优先级从1~10,10最大,优先级越高抢到CPU概率越高
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo04 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr,"飞机");
Thread t2 = new Thread(mr,"坦克");
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
}
}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo04 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t1 = new Thread(mr,"飞机");
Thread t2 = new Thread(mr,"坦克");
//
// System.out.println(t1.getPriority());
// System.out.println(t2.getPriority());
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
//
}
}
设置为守护线程
守护进程更通俗的来说就是“备胎”,非守护进程就相当于你的女神,当非守护进程执行完毕之后,守护进程会陆续结束,就好比你追到你女神了,然后官宣了,然后“备胎”看见了,慢慢的慢慢的就对你疏远了
应用场景:
当聊天界面关闭以后,传输文件就没必要执行了
出让线程
插入线程
线程的生命周期
JVM里是没有运行状态的,这里只是为了方便理解。
线程安全问题
同步代码块
为了解决线程的随机性,在操作一些共享数据的代码时,会把作共享数据的代码锁起来
特点:锁默认打开,有一个进程进去了,锁自动关闭;里面的代码全部执行完毕,线程出来,锁自动打开
Lock锁
手动上锁与开锁
线程池
1.创建一个池子,池子中是空的
2.提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
3.但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
Executors:线程池的工具类通过调用方法返回不同类型的线程池对象。
自定义线程池
什么时候才会创造临时线程
当核心线程都在忙而且队伍当中已经排满了任务,这个时候才会创建临时线程
当线程池满负荷运行时,就是触发任务拒绝策略
public class MyThreadPoolDemo {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,//核心线程数
6,//最大线程数
60,//空闲线程存活时间
TimeUnit.SECONDS,//单位
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//创建线程工厂
new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略
);
}
}
线程池多大合适
最大并行数
CPU密集型(项目计算多)
最大并行数+1
I/O密集型(读取文件多)
可以用工具thread dump测试时间