多线程笔记(狂神版)

【【狂神说Java】多线程详解】https://www.bilibili.com/video/BV1V4411p7EF?vd_source=9f87a7ce44630c11c1428c5f90d42fbb
图还没补

线程创建

3

继承Thread类

//线程创建方式1:继承thread1,重写run方法,调用start开启线程
public class Thread1 extends Thread {
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    public static void main(String[] args) {

        //创建线程对象,调用start方法
        Thread1 thread1 = new Thread1();
        thread1.start();

        //主线程
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习"+i);
        }
    }
}

/**
 * 多线程并发网络下载器
 * WebDownloader实现了网络图片下载功能;downloader方法输入为目标链接地址、下载图片文件名;结果为保存对应文件到本地
 * Thread2类中的run方法调用downloader方法;并且通过start实现多线程并发下载图片
 * 结果显而易见 执行具有无序性
 */
//多线程同步下载图片
public class Thread2 extends Thread {
    private String url;
    private String name;

    public Thread2(String url, String name) {
        this.url = url;
        this.name = name;
    }

    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, name);
        System.out.println("文件名" + name);
    }

    public static void main(String[] args) {
        Thread2 thread21 = new Thread2("https://img-blog.csdnimg.cn/2711126564c842689248e53bbf4d85e8.png", "t1.png");
        Thread2 thread22 = new Thread2("https://img-blog.csdnimg.cn/4b97a32c6d9f4caa8617099065d02e3c.png", "t2.png");
        Thread2 thread23 = new Thread2("https://img-blog.csdnimg.cn/419537bd2d5e4fdfaa70fb8b8ed17663.png", "t3.png");
        thread21.start();
        thread22.start();
        thread23.start();
    }
}

//下载器
class WebDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("io异常,downloader方法出现问题");
        }
    }
}

实现Runnable接口

//线程创建方式2:重写Runnable,重写run方法,执行线程丢入runnable接口实现类,调用start开启线程
public class Thread3 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在看代码"+i);
        }
    }

    public static void main(String[] args) {
        Thread3 thread3 = new Thread3();

        //创建线程对象,调用start方法(区分于继承Thread,将new的对象当参数new一个Thread)
        new Thread(thread3).start();

        //主线程
        for (int i = 0; i < 20; i++) {
            System.out.println("我在学习"+i);
        }
    }
}

实现Callable接口

对比

对比

高并发问题

买火车票

package thread;
//高并发模拟之买火车票
public class GetTicket implements Runnable{
    private int ticket = 10;

    @Override
    public void run() {
        while(true){
            if(ticket<=0) break;
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket--+"张票");
        }
    }

    public static void main(String[] args) {
        GetTicket t1 = new GetTicket();

        new Thread(t1,"xiaoming").start();
        new Thread(t1,"xiaohong").start();
        new Thread(t1,"xiaogang").start();
        //结果:除了结果不可预测,还有多个线程共用一张票的情况
    }
}

龟兔赛跑

public class Race implements Runnable {
    private static String winner;

    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if(Thread.currentThread().getName().equals("兔子") && i%50==0) {//兔子到50开始睡觉
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            if(isGameOver(i)) break;
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    private boolean isGameOver(int step){
        if(step == 100){
            winner = Thread.currentThread().getName();
            System.out.println("winner is "+winner);
        }
        return winner != null || step >= 100;
    }

    public static void main(String[] args) {
        Race race = new Race();
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟111").start();

    }
}

静态代理_Runnable原理

/**
 * 静态代理:
 * 设计一个接口,
 * 真实对象和代理对象都要实现这个接口,
 * 代理对象代理真实对象,
 * 真实对象专注做自己的事,
 * 代理对象代做真实对象做不到的事,
 * 这就是Runnable的原理-> new Thread(myThread).start();
 */
public class StaticProxy {
    public static void main(String[] args) {
        /*You you = new You();
        WeddingCompany weddingCompany = new WeddingCompany(you);
        weddingCompany.marry();*/
        //这么写和多线程实现Runnable一样
        new WeddingCompany(new You()).marry();
    }


}

interface Marry{
    void marry();
}

//真实角色,我去结婚
class You implements Marry{
    @Override
    public void marry() {
        System.out.println("我结婚了");
    }
}
//代理角色,婚庆公司帮我做before和after
class WeddingCompany implements Marry{
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }



    @Override
    public void marry() {
        before();
        this.target.marry();
        after();
    }

    void before(){
        System.out.println("收钱");
    }

    void after(){
        System.out.println("打扫");
    }
}

Lambda表达式

lamda

lambda函数式接口

/**
 * 推导了lambda表达式简化函数式编程的过程
 * 如果一个接口只有一个函数,实例化它相当于调用这个函数
 * 用lambda表达式可以极大简化调用过程
 */
public class TestLamda {

    //3.静态内部类
    static  class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }


    public static void main(String[] args) {
        Like like = new Like();
        like.lambda();

        Like2 like2 = new Like2();
        like2.lambda();

        //4.局部内部类
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }

        Like3 like3 = new Like3();
        like3.lambda();

        //5.匿名内部类
        like = new Like() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        //6.lambda简化
        ILike like4 = ()-> {
            System.out.println("i like lambda5");
        };
        like4.lambda();



    }


}

//1.函数接口
interface ILike{
    void lambda();
}

//2.实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}
//lambda表达式简化
public class Testlam {

    public static void main(String[] args) {
        int n = 5;
        //简化:可以不带参数类型;一个参数可以不带();void方法且只有一行可以不带{}
        Test1 myT = n1-> {return n1*n1;};
        Test2 myT2 = n1-> System.out.println(n1*n1);
        int re = myT.reSequre(n);
        System.out.println(re);
        myT2.reSequre(n);
    }

}

interface Test1{
    int reSequre(int n);
}
interface Test2{
    void reSequre(int n);
}

线程状态和实现

五个状态

停止线程stop

线程停止

package state;

/**
 * 线程停止方法:设定标志位,调用stop()方法使标志位变为0,进而停止线程
 */
public class TestStop implements Runnable {
    boolean flag = true;//标志位

    @Override
    public void run() {
        int i = 0;
        while (flag){//停止控制
            System.out.println("run thread"+i++);
        }

    }
    //停止线程
    public void stop(){
        this.flag = false;
    }


    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();//线程
        
        //主线程
        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if(i==900){
                testStop.stop();
                System.out.println("停止 i="+i);
            }
        }
    }
}

线程休眠sleep(进入阻塞)

sleep

//sleep模拟时钟
public class TimeClock {
    public static void main(String[] args) {
        Clock clock = new Clock(10);
        new Thread(clock).start();

    }
}

class Clock implements Runnable{
    @Override
    public void run() {
        this.clock();
    }

    private int clk;

    public Clock(int clk) {
        this.clk = clk;
    }

    void clock(){
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("time:"+this.clk--);
            if(clk<0){
                System.out.println("time out");
                break;
            }
        }


    }
}

线程礼让yield(进入就绪)

yield

yield代码

执行结果:可能礼让成功,abab;可能礼让失败,aabb

本质是让进程由执行变为就绪,竞争下一次的执行机会;取决于调度算法

线程强制执行join

join

join代码

执行结果:main中 i==200时 执行thread中的语句直到结束,并且其他线程阻塞

观测线程状态Thread.State

state

state1

state2

结果:

NEW——RUNNABLE——若干个TIMED-WAITIN——TERMINATED

新建 运行/就绪 睡眠(阻塞) 终止

线程优先级

优先级

优先级1

优先级2

优先级3

优先级4

守护daemon线程

守护线程

/**
 * 守护线程,可以不用确保其运行完毕
 * 运行结果:manba out之后,god像蛆一样再运行了几句,然后痛苦的似了😋
 */
public class Main {
    public static void main(String[] args) {
        God god = new God();
        Man man = new Man();

        Thread thread1 = new Thread(god);
        Thread thread2 = new Thread(man);
        thread1.setDaemon(true);//守护线程,不必等到执行完毕就可以结束

        thread1.start();
        thread2.start();
    }
}

class God implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("老登赖着不死😓");
        }
    }
}

class Man implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("牢大别肘┭┮﹏┭┮");
        }
        System.out.println("man!haha,what can i say?manba out!");
    }
}

线程同步

形成条件:队列+锁(synchronized)

优点:确保安全

缺点:挂起;性能问题(上下文切换 调度 优先级倒置)

同步方法

用于修饰方法,等同于给该方法加锁(该方法执行完毕才释放锁)

锁

同步块

同步块:将代码放在同步块内,obj对象的使用将加锁

一般对需要增删改的对象加锁

CopyOnWriteArrayList

一个实现好的安全的list

结果:10000 ;不会出现重复添加到同一个内存的情况

Lock

ReentrantLock:可重入锁

生产者消费者问题

管程法

/**
 * 生产者消费者问题
 * 管程法
 * 用synchronized机制实现同步:
 * 缓冲区大小为10,生产者遇到满或者消费者遇到空则wait()(注意使用了循环判断),此时这些线程阻塞;
 * 每个线程即将结束时notifyAll()唤醒所有进程(所有阻塞进程就绪),再次判断是缓冲区是否满足条件
 */
public class ProCon {
    public static void main(String[] args) {
        Container container = new Container();
        Productor productor = new Productor(container);
        Consumer consumer = new Consumer(container);
        productor.start();
        consumer.start();

    }
}

class Productor extends Thread{
    Container container;

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

    @Override
    public void run() {
        try {
            product(container);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    public void product(Container container) throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            container.push(new Chicken(i));
        }
    }
}

class Consumer extends Thread{
    Container container;
    public Consumer(Container container) {
        this.container = container;
    }
    @Override
    public void run() {
        try {
            consume();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    public void consume() throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            container.pop();
        }
    }

}

class Chicken{
    int id;
    public Chicken(int id) {
        this.id = id;
    }
}


class Container{
    private Chicken[] chickens = new Chicken[10];
    private int count = 0;
    //private final ReentrantLock lock = new ReentrantLock();//这个作用和synchronized一样,可以搭配wait和notify使用

    public synchronized void push(Chicken chicken) throws InterruptedException {

        while(count == chickens.length){//这里用while不用if 避免出现唤醒所有生产者但是缓冲区大小不够的问题
            this.wait();
        }
        chickens[count++] = chicken;
        System.out.println("第"+count+"个位置放置了鸡"+chicken.id);
        Thread.sleep(10);
        this.notifyAll();//唤醒所有进程(让所有进程都就绪)
    }

    public synchronized Chicken pop() throws InterruptedException {

        while(count == 0){//同上
            this.wait();
        }
        System.out.println("第"+count+"个位置的鸡"+chickens[count-1].id+"被取走了");
        Thread.sleep(10);
        this.notifyAll();
        return chickens[--count];
    }
}

信号灯法

synchronized机制实现同步;flag信号与wait、notify共同实现谁执行(flag=0生产,flag=1消费;与flag不符则wait(),每次执运行完毕notifyAll();每次执行后flag取反)

线程池

posted @ 2024-01-21 23:36  AUTI_SMER  阅读(66)  评论(0)    收藏  举报