学习线程,我们先来了解了解什么是进程?什么是线程
进程:就是在操作系统中运行的程序
线程:就是进程的一个执行单元,或者一条执行路劲
比如:我们打开应用商店,这个应用商店就是一个进程,应用商店里面也可以同时下载很多应用,每个应用的下载就是线程
一个进程至少有一个线程,一个进程里面如果有多个线程,我们称这个进程为多线程进程
我们先来看看程序没有多线程是怎样运行的
现在有一个售票的窗口 Ticket ,里面有可以买票的功能, 模拟两个人进行购票
public void buyTicket(String name) {
for (int i = 0; i < 5; i++) {
System.out.println(name + "购买动车票");
}
}
public static void main(String[] args) {
Ticket ticket = new Ticket();
ticket.buyTicket("小明");
System.out.println(".................");
Ticket ticket2 = new Ticket();
ticket2.buyTicket("小红");
}
我们发现程序是 按照 顺序执行的,相当于购票窗口只有一个,得等到小明完成才能购票
小明买完票了,程序出错了,后面的人就不要买票了,恭喜小明包了一辆动车,这显然是不合理的,因此就需要多个窗口进行售票,这就是多线程的使用
线程的创建
在java中,应该怎么创建线程呢?
1. 继承Tread类,重写Run方法
public class Ticket extends Thread {
private String name;
@Override
public void run() {
Thread.currentThread().setName(name+"的线程");
for (int i = 0; i < 300; i++) {
System.out.println(Thread.currentThread().getName()+ " 购买动车票");
}
}
public static void main(String[] args) {
//创建线程1
Ticket ticket = new Ticket();
//创建线程2
Ticket ticket2 = new Ticket();
ticket2.name="小红";
ticket.name="小明";
//开始线程
ticket.start();
ticket2.start();
}
}
2.实现runable接口
public class Ticket implements Runnable {
private String name;
@Override
public void run() {
for (int i = 0; i < 300; i++) {
System.out.println(Thread.currentThread().getName() + " " + name + "购买动车票");
}
}
public static void main(String[] args) {
//创建线程1
Ticket ticket = new Ticket();
ticket.name = "小明";
Thread thread = new Thread(ticket);
//开启线程 thread
thread.start();
ticket.name = "小红";
Thread thread2 = new Thread(ticket);
//开启线程 thread2
thread2.start();
}
}
3.实现Callable接口,使用FutureTask
public class Ticket implements Callable<Object> {
private String name;
@Override
public Object call() throws Exception {
for (int i = 0; i < 300; i++) {
System.out.println(Thread.currentThread().getName() + " " + name + "购买动车票");
}
return null;
}
public static void main(String[] args) {
//创建线程1
Ticket ticket = new Ticket();
ticket.name = "小明";
FutureTask<Object> task = new FutureTask<>(ticket);
//开启线程 thread
Thread thread = new Thread(task);
thread.start();
//创建线程2
ticket.name = "小红";
FutureTask<Object> task2 = new FutureTask<>(ticket);
Thread thread2 = new Thread(task2);
//开启线程 thread2
thread2.start();
}
}
三种创建线程的结果是一样的
输出结果:
这里可以看出线程是在同时进行的,谁优先抢到CPU执行权谁先执行
面试必问:
创建线程有三种方式:
继承Thread类,重写run方法
实现Runnnable接口,重写run方法
实现Callable接口,重写 call 方法,使用FutureTask
这三种有什么差别呢?开发中应该使用什么方式
开发中建议使用 实现接口的方式创建 实现 Runnable(不可抛出异常) 实现 Callable (可以抛出异常)
我们都知道类可以多实现,只能单一继承,如果使用继承thread来创建线程,大大增加了局限性
其次,继承Thread方式创建多线程,也浪费了资源,几个线程就创建了几个对象,而其他两个只创建一个公享就行
线程的优先级
线程的执行,也是有优先级的,优先级较高的 更优于 优先级较低 ,也就是说,优先级更高更容易抢占到CPU执行
注意:只是概率更高,并不是一定优先执行
我们可以去设置线程的优先级
MAX_PRIORITY 最大优先级 取值10
MiN_PRIORITY 最小优先级 取值1
NORM_PRIORITY 默认优先级 取值 5
我们还可以通过
getPriority() 方法获取线程的优先级
setPriority() 方法改变线程的优先级
public class Ticket implements Runnable {
private String name;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// System.out.println(Thread.currentThread().getName() + " " + name + "购买动车票");
}
}
public static void main(String[] args) {
//创建线程1
Ticket ticket = new Ticket();
ticket.name = "小明";
Thread thread = new Thread(ticket);
//开启线程 thread
thread.start();
ticket.name = "小红";
Thread thread2 = new Thread(ticket);
//开启线程 thread2
thread2.start();
//获取线程优先级
System.out.println(thread.getPriority());
System.out.println(thread2.getPriority());
}
}
可以看到未设置优先级之前,默认为5
现在我们给小明的线程设置优先级为10
public class Ticket implements Runnable {
private String name;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
// System.out.println(Thread.currentThread().getName() + " " + name + "购买动车票");
}
}
public static void main(String[] args) {
//创建线程1
Ticket ticket = new Ticket();
ticket.name = "小明";
Thread thread = new Thread(ticket);
//设置优先级 最大 10
thread.setPriority(Thread.MAX_PRIORITY);
//开启线程 thread
thread.start();
ticket.name = "小红";
Thread thread2 = new Thread(ticket);
//开启线程 thread2
thread2.start();
//获取线程优先级
System.out.println(thread.getPriority());
System.out.println(thread2.getPriority());
}
}
SpringBoot项目统一结果,统一异常,同一日志
面试官:说说 springboot 自动配置原理?
SpringBoot 中的自带工具类,开发效率增加一倍