Files
Java-Basic-and-Advanced/线程.md
2026-01-07 16:14:38 +08:00

13 KiB
Raw Blame History

线程

进程和线程

进程介绍:

image-20251226164954480

image-20251226170130636

线程Thread介绍

进程可以同时执行多个任务,每个任务就是线程:

多线程的作用:

提升执行效率,使更多进程可以并行执行

服务器必须用多线程

Java中开启线程的方式

1:继承Thread类

案例:

 public static void main(String[] args) {
        /*
         * 继承Thread类
         *         重写run方法
         *         将线程任务代码写在run方法
         *         创建对象
         *         对象名.start开启线程
         * 只有调用start方法才会开启一个新线程
         */
        Demo d1 = new Demo();
        Demo d2 = new Demo();
        d1.start();
        d2.start();
    }
}

class Demo extends Thread {
    @Override
    public void run() {
        for (int i = 1; i <= 200; i++) {
            System.out.println("打印了" + i);
        }
    }
}

注意:

image-20251226175706557

2实现Runnable接口

/*
    方法2 实现runnable接口
    编写一个类实现接口
    重写run方法
    创建线程任务资源(就是创建对象)
    然后创建线程对象,将任务资源传入,走构造方法
    使用线程对象调用start方法
     */
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();
        Thread tr = new Thread(mr);
        tr.start();
    }
}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println("八奈见杏菜");
    }
}

3实现Callable接口(有结果返回)

public class ThreadDemo3 {
    public static void main(String[] args) throws Exception {
        /*
        创建一个类实现Callable接口
        重写call方法
        创建线程任务资源对象
        创建线程任务对象封装线程任务资源FutureTask
        创建线程对象传入线程任务
        使用线程对象调用start方法开启线程
         */
        MyCallAble mc = new MyCallAble();
        FutureTask<Integer> ft = new FutureTask<>(mc);
        Thread t = new Thread(ft);
        t.start();
        Integer result = ft.get();
        System.out.println(result);
    }
}

class MyCallAble implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;

        }
        return sum;
    }
}

尽量选择后两个,拓展性更好

线程的方法

image-20251226195404148

名字相关:

image-20251226195311173

休眠线程:

image-20251226195657226

线程调度方法:

Java是抢占式调度

image-20251226200310813

守护线程

final void setDaemon(boolean on );

image-20251226200636908

如图代码所示t2守护t1t1线程任务结束t2也结束(不是立刻结束t2会在苟活一会儿)

哪个线程对象调用setDaemon方法这个线程就是守护线程

线程的安全与同步

image-20251227180059497

1.同步代码块:

image-20251227181232243

使用同步代码块指定锁对象时,用类的字节码对象

共享数据要用static修饰

2.同步方法:

image-20251227182957021

3.Lock锁

public static void main(String[] args) {
        TicketShop1 ts = new TicketShop1();
        Thread t1 = new Thread(ts);
        Thread t2 = new Thread(ts);
        Thread t3 = new Thread(ts);
        t1.start();
        t2.start();
        t3.start();
    }
}

class TicketShop1 implements Runnable{
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            //上锁
            try {
                lock.lock();
                if (ticket == 0){
                    break;
                }
                System.out.println("卖出了"+ticket+"号票");
                ticket--;
            } finally {
                //记得关闭锁
                lock.unlock();
            }
        }
    }
}

附加知识点:死锁:

image-20251227184706346

线程通信

image-20251228190234137

两条线程交替执行案例:

public static void main(String[] args) {
        Print p = new Print();
        Thread t1= new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (Print.class) {
                        try {
                            p.print1();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (Print.class) {
                        try {
                            p.print2();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        });

        t2.start();
    }
}

class Print{
    private int flag = 1;
    public void print1() throws InterruptedException {
        if (flag != 1){
            //wait只能通过锁对象进行调用
            Print.class.wait();
        }
        System.out.print("八");
        System.out.print("奈");
        System.out.print("见");
        System.out.print("杏");
        System.out.print("菜");
        System.out.println();
        flag = 2;
        //notif拥有空唤醒的权利
        Print.class.notify();
    }
    public void print2() throws InterruptedException {
        if (flag != 2){
            Print.class.wait();
        }
        System.out.print("温");
        System.out.print("水");
        System.out.print("佳");
        System.out.print("树");
        System.out.println();
        flag = 1;
        Print.class.notify();

    }
}

注意事项:

image-20251228190304630

若想提升效率使用ReentrantLock实现同步获取Condition对象

image-20251228191729896

注意:第一次指定线程等待时,绑定了线程

三条线程交替执行案例:

public static void main(String[] args) {
        Printer p = new Printer();
        Thread t1= new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                        try {
                            p.print1();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                }
            }
        });
        t1.start();
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                        try {
                            p.print2();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                }
            }
        });
        t2.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        p.print3();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }).start();
    }
}

class Printer{
    private int flag = 1;
    ReentrantLock lock = new ReentrantLock();
    //调用newCondition来获取条件对象以此来指定线程
        Condition c1 = lock.newCondition();
        Condition c2 = lock.newCondition();
        Condition c3 = lock.newCondition();

    public void print1() throws InterruptedException {
        lock.lock();
        if (flag != 1){
            //第一次调用await方法时绑定了线程
            c1.await();
        }
        System.out.print("八");
        System.out.print("奈");
        System.out.print("见");
        System.out.print("杏");
        System.out.print("菜");
        System.out.println();
        flag = 2;
        c2.signal();
        lock.unlock();
    }
    public void print2() throws InterruptedException {
        lock.lock();
        if (flag != 2){
            c2.await();
        }
        System.out.print("温");
        System.out.print("水");
        System.out.print("佳");
        System.out.print("树");
        System.out.println();
        flag = 3;
        c3.signal();
        lock.unlock();
    }

    public void print3() throws InterruptedException {
        lock.lock();
        if (flag != 3){
            c3.await();
        }
        System.out.print("温");
        System.out.print("水");
        System.out.print("梦");
        System.out.print("子");
        System.out.println();
        flag = 1;
        c1.signal();
        lock.unlock();
    }
}

生产者消费者模式:

image-20251228193330122 image-20251228193429569

生产者消费者案例:

image-20251228193308023

线程生命周期:

image-20251228194046082

线程池:

重点:自定义线程池

image-20251228200135970

拒绝策略用的最多的只有第一种AbortPolicy

image-20251228200427425

任务队列:

image-20251228200929336

总结:

image-20251228200820075

案例:

public class Demo3 {
    public static void main(String[] args) {
        ThreadPoolExecutor tp = new ThreadPoolExecutor(
                3,//核心数
                6,//最大核心数
                10,//空闲时间
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(10),//排队人数
                Executors.defaultThreadFactory(),//线程对象任务工厂,基本为固定
               new ThreadPoolExecutor.AbortPolicy()//拒绝策略,基本只用这个方法
        );
        for (int i = 1; i <17 ; i++) {
            tp.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "调用了hhh");
                }
            });
        }
        tp.shutdown();
    }
}

单例设计模式:

image-20251228204750037

两种方式:

饿汉式:简单不烧脑

直接创建出对象 而不是调用方法的时候再创建对象

懒汉式:(延迟加载模式):

image-20251228204926855