基础知识
- 什么是线程
- 被包含在进程之中, 可以调度的最小单位
- 应用软件中互相独立,可以同时运行的功能
- 什么是进程
- 程序的基本执行实体
总结:
- 什么是多线程?
- 有了多线程,可以让程序同时做多件事情
- 多线程有什么作用?
- 提供程序的运行效率
- 并发是什么?
- 在同一时刻,有多个指令在单个 CPU 上交替执行
- 并行是什么
- 在同一时刻,有多个指令在单个 CPU 上同时执行
在线程中进行并发和并行
多线程的实现方式
第一种继承 Thread 类方式实现:
- 定义一个类继承 Thread
- 重写 run 方法
- 创建对象实例
以 Runnable 接口的方式实现
- 实现Runnable 接口
- 重写方法
- 创建实例
- 将实例放入 Thread 类对象中
Callable接口
有返回值,可以获得多线程的结果
特点:
- 创建一个类实现Callable接口
- 重写call方法
- 创建实例对象
- 创建FutureTask对象管理线程结果
- 创建Thread类对象 获取结果
常见的成员方法
演示方法:
getName()和setName()
返回线程的名字:
public class Mythread_01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "@" + i);
}
}
}
返回的默认名字格式为Thread-序号
- 使用setname
- 使用Thread(String name)
- 但是需要在继承类中使用super方法把带有String的构造方法写出来
线程的优先级
抢占式调度特点:随机
//使用setPriority来设置优先级
t1.setPriority(1);
t2.setPriority(10);
t2.start();
t1.start();
守护线程
当其他非守护线程执行完毕,守护线程会陆续结束
当主线程结束,守护线程是跟着结束
插入线程
线程.join()
可以讲线程提前用完
线程的生命周期
线程安全问题
- 当线程被共享后,其中的数据也会被其他线程修改导致不安全
- 解决方式:把共享的数据锁起来
synchronized 锁的特点:
- 解决方式:把共享的数据锁起来
- 锁默认打开,有线程进去自动关闭
- 代码全部执行完毕,锁自动打开
锁(类的字节码->唯一对象)
同步方法
lock锁
标准写法:
Lock lock = new ReentrantLock();
while(true){
// synchronized (Myrunnable.class){
lock.lock();
try {
if(ticket == 100){
break;
}else{
Thread.sleep(10);
ticket++;
System.out.println(Thread.currentThread().getName() + " sell " + ticket + " tickets");
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
死锁
死锁是一种错误,需要我们去避免的
特点:
- A锁等着拿B锁
- B锁等着拿A锁
- 互相卡死
生产者和消费者
完整过程:
常见方法
代码执行的流程:
- 循环
- 同步代码块
- 判断共享数据是否到了末尾(到了末尾)
- 判断共享数据是否到了末尾(未到末尾)
分为三块代码:
Desk:控制消费者和生产者的行为
package 生产者消费者;
public class Desk {
//Desk:控制生产者和消费者的行为
// 是否有面条
public static int foodFlag = 0;
//制造的个数
public static int count = 10;
//锁对象
public static Object lock = new Object();
}
Cook:生产者
package 生产者消费者;
public class Cook extends Thread {
@Override
public void run() {
while (true) {
synchronized (Desk.lock) {
if (Desk.count == 0) { //桌子上的食物做够了
break;
}else{
//判断是否有食物
if(Desk.foodFlag == 1){ //如果有食物 等待消费者来吃
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else{
//如果没有食物 做
//修改食物状态
System.out.println("厨师做了一碗面条");
Desk.foodFlag = 1;
//叫醒消费者吃
Desk.lock.notifyAll();
}
}
}
}
}
}
Foodie:消费者
package 生产者消费者;
public class Foodie extends Thread{
@Override
public void run() {
while(true){
synchronized (Desk.lock){
if(Desk.count == 0){ //桌子上的食物做够了
break;
}else {
//判断桌子上有没有面条
if(Desk.foodFlag == 0){
//如果没有 就等待
try {
Desk.lock.wait(); //让线程等待
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else{ //如果有 直接开吃
Desk.count--;
System.out.println("吃货吃了一碗,还剩" + Desk.count + "碗!");
//唤醒厨师! 份数-1
Desk.lock.notifyAll();
//修改桌子的状态
Desk.foodFlag = 0;
}
}
}
}
}
}
阻塞队列方式
实现类:
ArrayBlockingQueue
LinkedBlockingQueue
队列和链表自带锁
线程的状态
七大状态:
线程中的栈
当在run方法中创建了一个集合,那么每一个线程都会维持一个创建的集合(类似于static)
线程池
代码:
自定义线程池
最大并行数
- 什么是最大并行数?
就是电脑的核心处理单元和线程,这里是八核十六线程
计算类型多:
读取文件或者数据库比较多: