# 线程 ## 进程和线程 ### 进程介绍: ![image-20251226164954480](https://gitee.com/icecat2233/picture/raw/master/20251226164956071.png) image-20251226170130636 ### 线程Thread介绍: 进程可以同时执行多个任务,每个任务就是线程: ### 多线程的作用: 提升执行效率,使更多进程可以并行执行 服务器必须用多线程 ## Java中开启线程的方式: ### 1:继承Thread类: 案例: ```Java 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](https://gitee.com/icecat2233/picture/raw/master/20251226175707664.png) ### 2:实现Runnable接口 ```java /* 方法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接口(有结果返回) ```java public class ThreadDemo3 { public static void main(String[] args) throws Exception { /* 创建一个类实现Callable接口 重写call方法 创建线程任务资源对象 创建线程任务对象,封装线程任务资源(FutureTask) 创建线程对象传入线程任务 使用线程对象调用start方法开启线程 */ MyCallAble mc = new MyCallAble(); FutureTask ft = new FutureTask<>(mc); Thread t = new Thread(ft); t.start(); Integer result = ft.get(); System.out.println(result); } } class MyCallAble implements Callable{ @Override public Integer call() throws Exception { int sum = 0; for (int i = 1; i <= 100; i++) { sum += i; } return sum; } } ``` ### 尽量选择后两个,拓展性更好 ## 线程的方法 ![image-20251226195404148](https://gitee.com/icecat2233/picture/raw/master/20251226195406047.png) ### 名字相关: ![image-20251226195311173](https://gitee.com/icecat2233/picture/raw/master/20251226195312281.png) ### 休眠线程: image-20251226195657226 ### 线程调度方法: Java是抢占式调度 image-20251226200310813 ### 守护线程 `final void setDaemon(boolean on );` image-20251226200636908 如图代码所示,t2守护t1,t1线程任务结束,t2也结束(不是立刻结束,t2会在苟活一会儿) 哪个线程对象调用setDaemon方法,这个线程就是守护线程 ## 线程的安全与同步 image-20251227180059497 ### 1.同步代码块: ![image-20251227181232243](https://gitee.com/icecat2233/picture/raw/master/20251227181233315.png) **使用同步代码块指定锁对象时,用类的字节码对象** **共享数据要用static修饰** ### 2.同步方法: image-20251227182957021 ### 3.Lock锁: ```Java 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 ### 两条线程交替执行案例: ```Java 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 注意:第一次指定线程等待时,绑定了线程 ### 三条线程交替执行案例: ```Java 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](https://gitee.com/icecat2233/picture/raw/master/20251228200428737.png) **任务队列:** image-20251228200929336 ### 总结: image-20251228200820075 ### 案例: ```Java 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