多线程知识点

1.多线程

在这里插入图片描述
在这里插入图片描述
例如:一个短视频,一个线程复制管理视频,一个线程负责管理声音,一个线程负责管理弹幕
进程:Process,程序一旦开始运行就是是一个进程
线程:Thread,一个程序运行后,里面就包含了多个线程

真正的多线程是指有多个cpu,即多核。如果是模拟的多线程,即只有一个cpu,在同一时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错误

2.线程的创建

1.继承Thread类
线程不一定立即执行,听从cpu的安排,交替执行

//实现步骤
1.继承Thread
2.重些run方法
3.对象. start()启动线程
public class StartThread extends Thread
{
@Override
public void run()
{
}
}
StartThread a=new StartThread();
a.start()

2.实现Runnable接口
接口实现类对象能被多个线程使用
1.实现接口
2.编写线程方法
3.开启线程,通过实现Runnable接口来创建线程,启动线程时需要通过Thread对象。

PrimeRun p = new PrimeRun(143);
new Thread(p).start();

并发问题:

3.实现Callable接口

3.静态代理

使用步骤
1.需要代理对象、实际对象,以及一个抽象接口
2.代理对象、实际对象都要实现接口
3.代理对象中创建构造方法,方法参数为接口类对象
4.在代理对象中定义抽象接口类对象来接收构造方法的参数对象
5.在代理对象中接口的实现方法中,用接收到的变量接口对象调用实现的接口方法
逻辑,通过代理对象的有参构造,将实际对象以参数的形式传递到代理类中,然后在代理类接口的实现方法中,调用实际类中的实现方法

4.线程停止

1.设立外部标志位,定义一个公开的方法,通过改变标志位来结束进程
在这里插入图片描述

5.线程休眠

应用

1.模拟网络延时
通过延时可以发现多线程中出现的问题,如数据同步性
2.倒计时
每个对象都有一把锁,sleep不回释放锁

6.线程礼让

Thread.yield()
正在进行的线程,由运行态转为就绪态,然后由cpu在就绪态中选择另一个线程,礼让不一定百分百成功

7.线程强制执行

线程插队,强制执行插队的线程
在这里插入图片描述

8.观测线程的状态

Thread.getState()
线程的状态
1.创建
2.就绪
3.执行
4.阻塞
5.结束,线程一旦结束,就不能再被使用

9.线程的优先级

thread.setPriority()
在这里插入图片描述

10.守护线程

监控用户线程,用户线程结束,守护线程也结束
thread.setDaemon()
在这里插入图片描述

11.线程同步

并发:同一个对象被多个线程同时操作,如:秒杀,抢票
解决线程的不安全性:队列+锁,解决数据安全性
synchronized

//修饰代码块
synchronized(this){} //修饰当前类
synchronized(类.class){}//修饰其他类
//修饰方法
1.修饰静态方法
2.修饰非静态方法

案例代码:
class Thick implements Runnable
{
    private int num=10;
    Boolean flag=true;


    @Override
    public void run()
    {
        try {
            buy();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public void buy() throws InterruptedException {
        while (flag)
        {
            Thread.sleep(200);
            if (num>0)
                synchronized (this)
                {
                    System.out.println(Thread.currentThread().getName()+"买到了第"+num--+"票");
                }
            else
            {
                flag=false;
            }
        }
    }
    
 public class CarThick {
    public static void main(String[] args) {
        Thick thick=new Thick();
        new Thread(thick,"张三").start();
        new Thread(thick,"李四").start();
        new Thread(thick,"王二狗").start();
    }
}

12.死锁

在这里插入图片描述

13.Lock锁

synchronized锁的作用一样,在线程同步的情况下,保证数据的原子性

ReentrantLock//可重入锁
private final ReentrantLock lock=new ReentrantLock();
lock.lock();//加锁,在数据发生改变的地方,加锁
lock.uplock;//解锁,完成数据改动后,把锁给下一个线程

14.生产者与消费者-线程通信

1.生产者
2.消费者
3.线程池
4.消费品

管程法

//线程池
class SynContainer{
    // 需要一个容器大小
    Bug[] bugs = new Bug[10];
    // 容器计算器
    int count = 0;

    // 生产者放入bug
    public synchronized void push(Bug bug){
        // 如果容器满了,就需要等待消灭bug
        if(count==bugs.length){
            // 通知消灭bug者消灭,生产bug等待
            try {
                //导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
                this.wait();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 如果没有满,我们就需要继续生产bug
        bugs[count] = bug;
        count++;

        // 可以通知消灭者消灭了
        this.notifyAll();
        // notifyAll唤醒正在等待对象监视器的所有线程。
    }

    // 消灭者消灭bug
    public synchronized Bug pop(){

        // 判断能否消灭
        if (count == 0){
            // 等待生产者生产,消灭者等待
            try {
                this.wait();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // 如果可以消灭
        count--;
        Bug bug = bugs[count];

        // 消灭完了,通知生产者生产

        this.notifyAll();
        try {
            System.out.println("通知生产者");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return bug;

    }
//生产者
class Productor extends Thread{

    SynContainer container;

    public Productor(SynContainer container){
        this.container = container;
    }

    // 生产
    @Override
    public void run() {
        for (int i = 0; i <=100; i++) {
            container.push(new Bug(i));
            System.out.println("生产了"+i+"个bug");
        }
    }
}

//消费者
class Consumer extends Thread{

    SynContainer container;

    public Consumer(SynContainer container){
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            System.out.println("消灭了-->"+container.pop().id+"个bug");
        }
    }
}
//消费品
class Bug{
    int id;// bug编号
    public Bug(int id){
        this.id = id;
    }
}
//测试
public class ProviderAndConsumer
{
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Consumer(container).start();
    }
}

15.线程池

避免重复的创建销毁线程,减少资源浪费,类似于数据库连接池
在这里插入图片描述