一、线程
1.1 并发与并行的概念(重点)
- 程序: 一个固定逻辑与数据的集合就是程序 例如 俄罗斯方块 贪吃蛇
- cpu: 中央处理器 主要用于协调程序与硬件的工作
- 并发与并行
- 并发(高并发): 在同一一个时间段 执行两个 或者多个程序的 单核cpu 交互的执行 由于cpu切换的速度比较块
可能产生的误区 是同时执行 是交替执行 - 并行:在同一个时刻 执行两个或者是多个程序的时候 多核cpu 同时执行 目前电脑都是多核的cpu
例子:看小电影 听音乐 例子:玩游戏 键盘侠
- 并发(高并发): 在同一一个时间段 执行两个 或者多个程序的 单核cpu 交互的执行 由于cpu切换的速度比较块
1.2 进程与线程(了解)
1. 进程:运行在内存中的程序就是进程 例子:idea 百度网盘 画图的工具
2. 线程:通向cpu的执行的路径就是线程
3. 线程分类:单线程与多线程
单线程: 只有一条通向cpu的执行的路径 就是单线程
多线程: 多条通向cpu的执行的路径 就是多线程
1.4 线程的五种状态
- 新建状态
- 就绪状态
- 阻塞状态/等待/睡眠
- 运行状态
- 死亡状态
1.3 创建线程的方式
1.3.1 继承Thread类
步骤:
- 定义一个类继承Thread
- 重写run()方法 执行线程的操作
- 实例化这个线程类的对象
- 调用start() 方法 开启线程
1.3.2 实现Runnable接口(重点)
步骤:
1. 定义一个类 实现 Runnable
2. 重写run()方法
3. 实例化线程对象 Thread 传递一个参数 Runnable 的实现类
4. 通过Thread对象调用方法开启线程 start()
1.3.3 使用匿名内部类创建多线程(重点)
package com.ahao;
public class Test01 {
public static void main(String[] args) {
//第一种方式
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
//第二种方式
new Thread(){
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}.start();
}
}
1.3.4 实现Callable接口(重点)
1. 定义一个类实现接口 Callable
2. 重写call()方法
3. 实例化 任务对象 FutureTask 构建一个Callable的实现类
4. 实例化线程对象 Thread 构建一个任务对象
5. 开启线程
6. 调用任务对象的get() 获取其返回值
线程类代码:
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
System.out.println(i);
sum+= i;
}
return sum;
}
}
测试类代码:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable callable = new MyCallable();
//实例化任务对象
FutureTask<Integer> task = new FutureTask<>(callable);
//构建任务对象
new Thread(task).start();
Integer sum = task.get();
System.out.println("1+2+......+99+100="+sum);
}
}
1.3.5 线程池
简介:用于来管理与维护线程
步骤:
1. 通过线程池的工具类来创建线程对象
2. 创建一个线程任务对象
3. 将任务对象提交线程池中
4. 通过get() 获取到线程执行完的结果
线程类代码1:
import java.util.concurrent.Callable;
public class MyCallable implements Callable {
@Override
public Object call() throws Exception {
return Thread.currentThread().getName()+"\t"+"666";
}
}
线程类代码2:
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"\t"+"Runnable");
}
}
测试类:
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(2);//设置线程数量
MyRunnable r1 = new MyRunnable();
MyRunnable r2 = new MyRunnable();
MyCallable callable = new MyCallable();
Future future = pool.submit(callable);
System.out.println(future.get());
pool.submit(r1);
pool.submit(r2);
pool.submit(r1);
pool.submit(r2);
pool.submit(r1);
}
}
二、线程中的方法(重要)
2.1 线程休眠
方法的名称 | 方法 的描述 |
---|---|
public static void sleep(long millis) | public static void sleep(long millis) |
2.2 守护线程
1. 守护线程:守护其它的线程 守护其它线程执行完操作 java中gc垃圾回收器 jav程序在运行期间 都会出现垃圾,这个九垃圾就是由gc来默默进行回收 gc就是一个守护的线程
2. 守护线程的死亡: 被守护的线程执行完操作 或者是死亡 那么守护线程也就是死亡
3. 一般守护线程都是守护主线程
方法的名称 | 方法的描述 |
---|---|
public final void setDaemon(boolean on) | 设置为守护线程 |
public final boolean isDaemon() | 测试该线程是否为守护线程 |
2.3 线程的优先级
2.3.1 优先级常量
常量的名称 | 常量的描述 |
---|---|
public static final int MAX_PRIORITY | 线程可以具有的最高优先级 |
public static final int MIN_PRIORITY | 线程可以具有的最低优先级 |
public static final int NORM_PRIORITY | 分配给线程的默认优先级 |
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
注意点:
A.线程的最高优先级是10 线程的最低优先级是1 范围 1-10
B.线程优先级越高 表示获取cpu执行权越大 并不一定会执行 java 抢占式调度
2.3.2 方法
方法的名称 | 方法的描述 |
---|---|
public final int getPriority() | 返回的是线程的优先级 |
public final void setPriority(int newPriority) | 更改线程的优先级 |
2.4线程常用的方法(重点)
方法的名称 | 方法的说明 |
---|---|
public final void stop() | 强迫线程停止执行 |
public static void yield() | 暂停当前正在执行的线程对象,并执行其他线程(礼让) |
public final void join() | 等待该线程终止(方法必须在线程开启之后进行调用) |
2.4.1 stop的代码演示
package com.qf.demo03;
public class MyThread extends Thread {
@Override
public void run() {
for (int i=1;i<=10;i++){
if (i==5){
//终止线程
stop();
}
System.out.println(i);
}
}
}
package com.qf.demo03;
public class Test01 {
public static void main(String[] args) {
//实例化线程对象
MyThread t = new MyThread();
t.start();
}
}
2.4.2 yield的代码演示
package com.qf.demo04;
public class MyThread extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(getName()+"\t"+i);
}
}
}
package com.qf.demo04;
public class Test01 {
public static void main(String[] args) {
MyThread t1= new MyThread();
t1.yield();
t1.start();
MyThread t2 = new MyThread();
t2.start();
}
}
2.4.3 join 方法代码演示
package com.qf.demo05;
public class MyThread extends Thread {
@Override
public void run() {
for (int i=0;i<100;i++){
System.out.println(getName()+"\t"+i);
}
}
}
package com.qf.demo05;
public class Test01 {
public static void main(String[] args) throws InterruptedException {
MyThread t1= new MyThread();
t1.start();
t1.join();
MyThread t2 = new MyThread();
t2.start();
}
}
三、Object 提供操作线程的方法(重点)
3.1 方法的介绍
方法的名称 | 方法的描述 |
---|---|
public final void wait() | 无限等待(需要被唤醒) |
public final void wait(long timeout) | 计时等待 |
public final void notify() | 唤醒在此对象监视器上等待的单个线程(一个) |
public final void notifyAll() | 唤醒在此对象监视器上等待的所有线程(多个) |
四、线程通信
4.1案例:
A.每一个窗口就是一个线程 使用线程来表示多窗口售票
B.数据共享 使用第二种方式来创建线程
C.定义一个变量来表示票数
D.循环售票
线程不安全案例代码:
public class MyRunnable implements Runnable{
//定义一个变量来记录票数
private int count=100;
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用循环一直买票
while (true){
if (count > 0) {
System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
count--;
}
}
}
}
public class Test01 {
public static void main(String[] args) {
//实例化MyRunnable对象
MyRunnable runnable = new MyRunnable();
//实例化线程
Thread t1 = new Thread(runnable);
t1.start();
//实例化线程
Thread t2 = new Thread(runnable);
t2.start();
//实例化线程
Thread t3 = new Thread(runnable);
t3.start();
}
}
4.2 第一种解决方案-同步代码块
1.语法:
synchronized(锁对象) {
可能产生问题的代码
}
2.注意点
A.锁的对象可以是任意的对象
B.所有线程锁的对象必须是同一个对象
3.作用:
解决数据共享安全的问题
解决代码:
public class MyRunnable implements Runnable{
//定义一个变量来记录票数
private int count=100;
//定义一个锁的对象
private Object obj = new Object();
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用循环一直买票
while (true){
synchronized (obj) {
if (count > 0) {
System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
count--;
}
}
}
}
}
4.3 第二种解决方案 -同步方法
1.语法:
访问修饰符 synchronized 返回值类型 方法的名称(参数列表) {
方法体
retrun 返回值
}
2.说明:同步方法可以是普通的成员方法 也可以是静态的方法
3.说明:
A.成员方法的锁的对象就是this
B.静态方法锁的对象是当前类的class对象
解决代码:
public class MyRunnable implements Runnable{
//定义一个变量来记录票数
private static int count=100;
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//使用循环一直买票
while (true){
showInfo();
}
}
//同步方法
public static synchronized void showInfo() {
if (count > 0) {
System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
count--;
}
}
}
4.4 第三种解决方案-锁
1.Lock 简介
A.Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
B.此实现允许更灵活的结构
2. 实现类ReentrantLock
3.方法
方法的名称 | 方法的描述 |
---|---|
void lock() | 获取锁 |
void unlock() | 释放锁 |
解决代码:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyRunnable implements Runnable{
//定义一个变量来记录票数
private int count=1000;
//实例化Lock锁对象
private Lock l = new ReentrantLock();
@Override
public void run() {
//获取锁对象
l.lock();
try {
Thread.sleep(500);
//使用循环一直买票
while (true){
if (count > 0) {
System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
count--;
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放锁对象
l.unlock();
}
}
}
五、死锁
- 死锁: A占用B的锁对象 B占用的A的锁对象 互补谦让 两个线程都处于等待状态 出现了死锁
六、生产者与消费者模式(重点)
6.1简介:
生产者不能一直生产,消费者不能一直消费
生产者生产产品 —> 等待消费者消费
消费者购买完产品—>等待生产者生产
6.2 案例代码:
产品类:
public class BaoZi {
public String pi;
public String xian;
//如果false 表示没有包子 为true表示有包子
public boolean flag = false;
}
线程类-01:
public class MyThread01 extends Thread {
private BaoZi baoZi;
public MyThread01(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
while (true) {
synchronized (baoZi){
try {
if (baoZi.flag) {
baoZi.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
baoZi.pi = "薄皮";
baoZi.xian = "肉馅";
System.out.println("生产了一个" + baoZi.pi + baoZi.xian + "的包子");
baoZi.flag = true;
baoZi.notify();
}
}
}
}
线程类-02:
public class MyThread02 extends Thread {
private BaoZi baoZi;
public MyThread02(BaoZi baoZi) {
this.baoZi = baoZi;
}
@Override
public void run() {
while (true) {
synchronized (baoZi){
try {
if (!baoZi.flag) {
baoZi.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我吃了一个" + baoZi.pi + baoZi.xian + "的包子");
baoZi.pi = null;
baoZi.xian = null;
baoZi.flag = false;
baoZi.notify();
}
}
}
}
测试类:
public class Test {
public static void main(String[] args) {
BaoZi baoZi = new BaoZi();
new MyThread01(baoZi).start();
new MyThread02(baoZi).start();
}
}