• 重学java基础----多线程


    参考于遇见狂神说视频以及学习笔记

    核心概念

    在这里插入图片描述

    线程创建的方式(重要

    在这里插入图片描述

    //方式一:继承Thread类,重写run()方法,调用start开启线程
    // 线程开启不一定立即执行,由cpu调度执行

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/14-15:41
     */
    //方式一:继承Thread类,重写run()方法,调用start开启线程
    // 线程开启不一定立即执行,由cpu调度执行
    
    public class TestThread1 extends  Thread{
        @Override
        public void run() {
            //线程体
            for (int i = 200; i > 0; i--) {
                System.out.println("我在学习多线程"+i);
            }
        }
    
        public static void main(String[] args) {
            //主线程
    
            //创建一个线程对象
            TestThread1 testThread1 =new TestThread1();
    
            //调用start方法开启线程
            testThread1.start();
    
            for (int i = 1000; i > 0; i--) {
                System.out.println("我在看代码"+i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    实现runnable接口,重写run方法,创建线程对象,执行线程丢入runnable接口实现类,调用start方法

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/14-15:58
     */
    //方式2:实现runnable接口,重写run方法,创建线程对象,执行线程丢入runnable接口实现类,调用start方法
    public class TestThread2 implements Runnable {
        @Override
        public void run() {
            //线程体
            for (int i = 200; i > 0; i--) {
                System.out.println("我在学习多线程"+i);
            }
        }
    
        public static void main(String[] args) {
            //主线程
            TestThread2 testThread2 =new TestThread2();
    
            new Thread(testThread2).start();
    
            for (int i = 1000; i > 0; i--) {
                System.out.println("我在看代码"+i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    两种方式总结

    在这里插入图片描述

    实现callable接口,开启多线程

    package com.Thread;
    
    import java.util.concurrent.*;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/14-16:28
     */
    public class TestThread4 implements Callable<Boolean> {
    
        @Override
        public Boolean call() throws Exception {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName()+" i="+i);
            }
            return true;
        }
    
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            TestThread4 testThread1 =new TestThread4();
            TestThread4 testThread2 =new TestThread4();
            TestThread4 testThread3 =new TestThread4();
    
            //创建执行服务:
            ExecutorService ser = Executors.newFixedThreadPool(3);
            //提交执行:
            Future<Boolean> result1 = ser.submit(testThread1);
            Future<Boolean> result2 = ser.submit(testThread2);
            Future<Boolean> result3 = ser.submit(testThread3);
            //获取结果:
            boolean r1 = result1.get();
            boolean r2 = result2.get();
            boolean r3 = result3.get();
            //关闭服务:
            ser.shutdownNow();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    使用runnable接口用到了静态代理的知识,
    真实对象和代理对象都要实现同一个接口
    代理对象要代理真实角色 使用静态代理的好处:

    1. 代理对象可以做很多真实对象无法做的事情
    2. 真实对象专注于做自己的事情
    package com.Thread;
    
    import javax.activation.MailcapCommandMap;
    import java.util.Map;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/14-16:45
     */
    //静态代理模式
    public class staticTest {
    
        public static void main(String[] args) {
            weddingCompany weddingCompany =new weddingCompany(new You());
    
            weddingCompany.HappyMarry();
    
        }
    }
    
    
    interface  Marry{
        void HappyMarry();
    }
    class You implements Marry{
    
        @Override
        public void HappyMarry() {
            System.out.println("小明要结婚了,很开心");
        }
    }
    
    class weddingCompany implements Marry{
    
        private Marry target;
    
        public weddingCompany(Marry target){
            this.target =target;
        }
    
        @Override
        public void HappyMarry() {
            before();
            this.target.HappyMarry();
            after();
        }
    
        private void after() {
            System.out.println("结婚后,收拾现场");
        }
    
        private void before() {
            System.out.println("结婚前,布置现场");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    线程的5大状态

    在这里插入图片描述
    在这里插入图片描述

    常用方法

    在这里插入图片描述

    如何停止线程

    1.建议线程正常停止—》利用次数,不建议死循环
    2.建议使用标志位—》设置一个标志位
    3.不要使用stop或destroy等过时或jdk不建议使用的方法

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-8:33
     * 测试stop
     1.建议线程正常停止---》利用次数,不建议死循环
     2.建议使用标志位---》设置一个标志位
     3.不要使用stop或destroy等过时或jdk不建议使用的方法
     *
     */
    
    
    public class Thread5 implements  Runnable {
    
        //1.设置一个标志位
        private boolean flag=true;
    
        @Override
        public void run() {
          int i=0;
          while (flag){
              System.out.println("run...thread"+i++);
          }
        }
    
        //2.设置一个公开的方法停止线程,转换标志位
        public void stop(){
            this.flag=false;
        }
    
        public static void main(String[] args) {
            Thread5 thread5=new Thread5();
            new Thread(thread5).start();
    
            //调用stop方法切换标志位,让线程停止
            for (int i = 1; i <=1000; i++) {
                System.out.println("main..."+i);
                if (i == 900) {
                    thread5.stop();
                    System.out.println("线程停止了。。。");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    线程休眠

    在这里插入图片描述

    • sleep()方法的用处:
    • 1.模拟网络延迟,放大线程中的并发问题
    • 2.模拟倒计时
    • 3.获取当前系统时间
    • 模拟倒计时
     package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-8:50
     *
     * sleep()方法的用处:
     * 1.模拟网络延迟,放大线程中的并发问题
     * 2.模拟倒计时
     * 3.获取当前系统时间
     */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    public class TestSleep {
    
        public static void main(String[] args) {
            try {
                testDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    
    
        public static void testDown() throws InterruptedException {
            int num=10;
            while (true) {
                Thread.sleep(1000);
                System.out.println(num--);
                if(num<=0){
                   break;
                }
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 打印当前系统时间
    
    package com.Thread;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.logging.SimpleFormatter;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-8:50
     *
     * sleep()方法的用处:
     * 1.模拟网络延迟,放大线程中的并发问题
     * 2.模拟倒计时
     * 3.获取当前系统时间
     */
    
    public class TestSleep {
    
        public static void main(String[] args) throws InterruptedException {
            //打印当前系统时间
            Date date=new Date(System.currentTimeMillis());//获取系统当前时间
            while (true) {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
                date=new Date(System.currentTimeMillis());//更新系统时间
            }
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    线程礼让

    在这里插入图片描述

    礼让不一定能成功,最终决定权在cpu如何调度

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-9:10
     *
     * 测试礼让,礼让不一定能成功,最终决定权在cpu如何调度
     */
    public class TestYield {
        public static void main(String[] args) {
            MyYile myYile=new MyYile();
            new Thread(myYile,"a").start();
            new Thread(myYile,"b").start();
        }
    
    }
    
    class MyYile implements Runnable{
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"线程开始执行");
            Thread.yield();//礼让
            System.out.println(Thread.currentThread().getName()+"线程执行结束");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Join介绍

    在这里插入图片描述

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-9:25
     * //join方法,相当于插队
     */
    public class TestJoin implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i <=500; i++) {
                System.out.println("vip会员开始执行" + i);
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            TestJoin testJoin = new TestJoin();
            Thread thread=new Thread(testJoin);
            thread.start();
    
            for (int i = 0; i < 200; i++) {
                if(i==100)
                thread.join(); //vip会员插队
                System.out.println("main开始执行"+i);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    线程状态的观测

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-9:37
     */
    public class TestThreadState {
        public static void main(String[] args) throws InterruptedException {
            Thread thread =new Thread(()->{
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("///");
            });
    
    
            //观察状态
            Thread.State state=thread.getState();
            System.out.println(state);
    
            //观察线程启动后
            thread.start();
            state=thread.getState();
            System.out.println(state);
    
            //
            while (state!=Thread.State.TERMINATED){ //只要线程不停止,就一直输出状态
                Thread.sleep(100);
                state=thread.getState(); //更新线程状态
                System.out.println(state);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    线程优先级

    注意:优先级高的不一定先执行,只不过是执行的概率较大

    在这里插入图片描述

    守护线程

    默认是false,代表用户线程(main线程),守护线程(Gc线程)
    在这里插入图片描述

    在这里插入图片描述

    线程同步(重要)

    什么是并发?

    在这里插入图片描述

    什么是线程同步?

    处理多线程问题时 , 多个线程访问同一个对象 , 并且某些线程还想修改这个对象 . 这时候我们就需要线程同步。线程同步其实就是一种等待机制 , 多个需要同时访问此对象的线程进入这个对象的等待池形成队列, 等待前面线程使用完毕 , 下一个线程再使用
    采用队列+锁的方式解决
    在这里插入图片描述

    线程不安全举例

    • 不安全的买票(会出现负数)
     package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-11:03
     * 

    * 模拟不安全的买票 * 线程不安全,票数有负数 */ public class TestUnsaveBuyTicket { public static void main(String[] args) { buyTicket buy = new buyTicket(); new Thread(buy, "wzl").start(); new Thread(buy, "zzz").start(); new Thread(buy, "www").start(); } } class buyTicket implements Runnable { private int ticketNums = 10; boolean flag = true; @Override public void run() { try { while (flag) { buy(); } } catch (InterruptedException e) { e.printStackTrace(); } } //买票 private void buy() throws InterruptedException { while (ticketNums <= 0) { flag = false; return; } Thread.sleep(10); //买票 System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 不安全的取票
    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-11:16
     * 不安全取钱
     * 两个人同时去银行取钱
     */
    public class TestMoney {
        public static void main(String[] args) {
    
            Account account=new Account(100,"结婚金钱");
    
            Bank you =new Bank(account,50,"你");
            Bank girl =new Bank(account,100,"女朋友");
    
            you.start();
            girl.start();
        }
    }
    
    //账户
    class Account {
        int money; //余额
        String name;//卡名
    
        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    
    }
    
    //银行,模拟取款
    class Bank extends Thread {
        Account account; //账户
    
        int drawmoney; //取的钱
        int nowmoney; //手里的钱
    
        public Bank(Account account, int drawmoney,String name) {
    
            super(name);
            this.account = account;
            this.drawmoney = drawmoney;
    
        }
    
        //用户取钱
        @Override
        public void run() {
            //钱不够
            if (account.money - drawmoney < 0) {
                System.out.println(Thread.currentThread().getName() + "钱不够,不能取");
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //卡内余额
            account.money = account.money - drawmoney;
            //手里的钱
            nowmoney = nowmoney + drawmoney;
            System.out.println(account.name + "余额为:" + account.money);
            System.out.println(this.getName() + "手里的钱" + nowmoney);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 线程不安全的集合

    由于ArrayList是线程不安全的,在测试添加10000条数据后,由于不安全会出现添加的数据不够10000条数据,因为会出现同时抢占同一块内存空间,然后会覆盖原先的值,因此不够10000条大小

     package com.Thread;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-11:52
     */
    public class unsafeList {
        public static void main(String[] args) {
            List<String> list =new ArrayList<>();
            for (int i = 0; i < 10000; i++) {
                new Thread(()->{
                    list.add(Thread.currentThread().getName());
                }).start();
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(list.size());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    如何解决线程不安全问题

    使用synchronized 关键词,构建synchronized 方法 和synchronized 块 .
    在这里插入图片描述
    需要修改内容的时候才使用synchronized同步方法,否则会浪费资源

    • 修改后的安全取票
    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-11:03
     * 

    * 模拟不安全的买票 * 线程不安全,票数有负数 */ public class TestUnsaveBuyTicket { public static void main(String[] args) { buyTicket buy = new buyTicket(); new Thread(buy, "wzl").start(); new Thread(buy, "zzz").start(); new Thread(buy, "www").start(); } } class buyTicket implements Runnable { private int ticketNums = 10; boolean flag = true; @Override public void run() { try { while (flag) { buy(); } } catch (InterruptedException e) { e.printStackTrace(); } } //买票,变为同步方法 private synchronized void buy() throws InterruptedException { while (ticketNums <= 0) { flag = false; return; } Thread.sleep(10); //买票 System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--); } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 修改后的银行取款

    注意:这里不能用synchronized直接修饰run()方法,由于变化的量是accout用户的余额,且两个人共享的资源是同一个账户,而不是共享的银行,因此需要使用同步块进行处理。
    同步块中的变量应该进行是增、删、改的变量

    package com.Thread;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-11:16
     * 不安全取钱
     * 两个人同时去银行取钱
     */
    public class TestMoney {
        public static void main(String[] args) {
    
            Account account=new Account(100,"结婚金钱");
    
            Bank you =new Bank(account,50,"你");
            Bank girl =new Bank(account,100,"女朋友");
    
            you.start();
            girl.start();
        }
    }
    
    //账户
    class Account {
        int money; //余额
        String name;//卡名
    
        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    
    }
    
    //银行,模拟取款
    class Bank extends Thread {
        Account account; //账户
    
        int drawmoney; //取的钱
        int nowmoney; //手里的钱
    
        public Bank(Account account, int drawmoney,String name) {
    
            super(name);
            this.account = account;
            this.drawmoney = drawmoney;
    
        }
    
        //用户取钱
        @Override
        public  void run() {
    
            synchronized (account){
                //钱不够
                if (account.money - drawmoney < 0) {
                    System.out.println(Thread.currentThread().getName() + "钱不够,不能取");
                    return;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //卡内余额
                account.money = account.money - drawmoney;
                //手里的钱
                nowmoney = nowmoney + drawmoney;
                System.out.println(account.name + "余额为:" + account.money);
                System.out.println(this.getName() + "手里的钱" + nowmoney);
            }
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 修改后的安全集合
    package com.Thread;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Vector;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-11:52
     */
    public class unsafeList {
        public static void main(String[] args) {
            List<String> list =new ArrayList<>();
            for (int i = 0; i < 30000; i++) {
                new Thread(()->{
                    synchronized (list) {
                        list.add(Thread.currentThread().getName());
                    }
                }).start();
            }
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(list.size());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    死锁

    • 定义

    在这里插入图片描述

    • 举例

    小红和小花进行化妆需要口红和镜子,两人互相拥有一个资源

    • 产生死锁的代码
    package com.Thread;
    
    import java.util.List;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-15:24
     */
    public class TestSiSuo {
        public static void main(String[] args) {
    
            Makeup girl1=new Makeup(0,"小红");
            Makeup girl2=new Makeup(1,"小花");
    
            girl1.start();
            girl2.start();
        }
    }
    class Lipstick{
    
    }
    class Mirror{
    
    }
    class Makeup extends Thread{
    
        //需要的资源只有一份,用static保证
        static Lipstick lipstick=new Lipstick();
        static  Mirror mirror=new Mirror();
    
        int choice;//选择
        String girlName;//女孩名字
    
    
        Makeup(int choice,String girlName){
            this.choice=choice;
            this.girlName=girlName;
        }
        @Override
        public void run() {
            try {
                makeup();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        //化妆,互相持有对方的资源
        private void makeup() throws InterruptedException {
            if(choice==0){
                synchronized (lipstick){//持有口红的锁
                    System.out.println(this.girlName+"获得了口红的锁");
                    Thread.sleep(1000);
                    synchronized (mirror){//1秒后想获得镜子
                        System.out.println(this.girlName+"获得了镜子的锁");
                    }
                }
    
            }else {
                synchronized (mirror){//持有镜子的锁
                    System.out.println(this.girlName+"获得了镜子的锁");
                    Thread.sleep(1000);
                    synchronized (lipstick){//1秒后想获得口红
                        System.out.println(this.girlName+"获得了口红的锁");
                    }
                }
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 解决死锁的代码
    package com.Thread;
    
    import java.util.List;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-15:24
     */
    public class TestSiSuo {
        public static void main(String[] args) {
    
            Makeup girl1=new Makeup(0,"小红");
            Makeup girl2=new Makeup(1,"小花");
    
            girl1.start();
            girl2.start();
        }
    }
    class Lipstick{
    
    }
    class Mirror{
    
    }
    class Makeup extends Thread{
    
        //需要的资源只有一份,用static保证
        static Lipstick lipstick=new Lipstick();
        static  Mirror mirror=new Mirror();
    
        int choice;//选择
        String girlName;//女孩名字
    
    
        Makeup(int choice,String girlName){
            this.choice=choice;
            this.girlName=girlName;
        }
        @Override
        public void run() {
            try {
                makeup();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        //化妆,互相持有对方的资源
        private void makeup() throws InterruptedException {
            if(choice==0){
                synchronized (lipstick){//持有口红的锁
                    System.out.println(this.girlName+"获得了口红的锁");
                    Thread.sleep(1000);
                }
                synchronized (mirror){//1秒后想获得镜子
                    System.out.println(this.girlName+"获得了镜子的锁");
                }
            }else {
                synchronized (mirror){//持有镜子的锁
                    System.out.println(this.girlName+"获得了镜子的锁");
                    Thread.sleep(1000);
                }
                synchronized (lipstick){//1秒后想获得口红
                    System.out.println(this.girlName+"获得了口红的锁");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    死锁避免的方法

    在这里插入图片描述

    Lock锁

    可重入锁

    在这里插入图片描述

    • 使用形式
      在这里插入图片描述
    • 举例代码
    package com.Thread;
    
    import java.beans.beancontext.BeanContextServiceRevokedListener;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-15:49
     */
    public class TestLock {
        public static void main(String[] args) {
            Ticket ticket =new Ticket();
    
            new Thread(ticket).start();
            new Thread(ticket).start();
            new Thread(ticket).start();
        }
    }
    
    class Ticket implements Runnable{
    
        int ticketNum=10;
        //定义lock锁
        private final ReentrantLock lock =new ReentrantLock();
        @Override
        public void run() {
            while (true){
                try {
                    lock.lock(); //加锁
                    if(ticketNum>0) {
                        System.out.println(ticketNum--);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        break;
                    }
                }finally {
                    lock.unlock(); //解锁
                }
    
    
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    synchronized vs lock

    在这里插入图片描述

    package com.Thread;
    
    import jdk.internal.dynalink.ChainedCallSite;
    
    /**
     * @Description
     * @autor wzl
     * @date 2022/8/16-16:07
     * 

    * 测试:生产者消费者模型--》利用缓冲区解决:管程法 * 生产者,消费者,产品,缓冲区 */ public class TestPc { public static void main(String[] args) { SynContainer synContainer= new SynContainer(); new productor(synContainer).start(); new consumer(synContainer).start(); } } class productor extends Thread { SynContainer synContainer; public productor(SynContainer synContainer){ this.synContainer=synContainer; } //生产 @Override public void run() { for (int i = 0; i < 100; i++) { synContainer.push(new chicken(i)); System.out.println("生产了"+i+"只鸡"); } } } class consumer extends Thread{ SynContainer synContainer; public consumer(SynContainer synContainer){ this.synContainer=synContainer; } @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println("消费了-->"+synContainer.pop().id+"只鸡"); } } } class chicken { int id; //产品标号 public chicken(int id) { this.id = id; } } class SynContainer { //定义一个容器,存放产品 chicken[] chickens = new chicken[50]; //定义计数器 int count = 0; //生产者放入产品 public synchronized void push(chicken chicken) { //如果容器满了,就等待消费者消费 if(count==chickens.length){ //通知消费者,生产者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果没有满,就放入产品 chickens[count]=chicken; count++; //可以通知消费者消费了 this.notify(); } //消费者消费产品 public synchronized chicken pop(){ //判断能否消费 if(count==0){ //通知生产者生产,消费者等待 try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //如果有产品,进行消费 count--; chicken chicken=chickens[count]; //吃完后,通知生产者生产 this.notify(); return chicken; } }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
  • 相关阅读:
    Ubuntu - 连接 ssh 网络错误
    esp8266 Task任务创建与执行
    vue164-自定义指令-全局自定义指令
    架构整洁之道(一)
    【云原生|K8s系列第2篇】:使用MiniKube创建第一个K8s集群
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY createTime DESC)的用法讲解(文心一言自动生成的博客)
    Elasticsearch语法知多少之Term query
    广东省2022下半年软考报名时间已定!
    干货 | 科研人的KPI怎么算,H指数和G指数是什么
    [ROS]在VS Code下编写代码,汇总问题及解决办法
  • 原文地址:https://blog.csdn.net/qq_38716929/article/details/126332241