• Java多线程03


    线程同步

    并发:多个线程访问同一个对象,造成数据不安全

    三个例子

    package com.guanxing.syn;
    
    public class UnsafeTicket {
        public static void main(String[] args) {
            BuyTicket station = new BuyTicket();
    
            new Thread(station, "苦逼的我").start();
            new Thread(station, "牛逼的你").start();
            new Thread(station, "可恶的黄牛党").start();
        }
    }
    
    class BuyTicket extends Thread {
        //票
        private int ticketNums = 10;
        boolean flag = true;
    
        @Override
        public void run() {
            while (flag) {
                buy();
            }
        }
    
        //买票的方法
        public void buy() {
            //判断是否有票
            if (ticketNums <= 0) {
                flag = false;
                return;
            }
            //模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //买票
            System.out.println(Thread.currentThread().getName()+"抢到了第"+ticketNums--+"张票");
        }
    }
    
    package com.guanxing.syn;
    
    //不安全的取钱
    //两个人去银行取钱
    public class UnsafeBank {
        public static void main(String[] args) {
            //账户
            Account account = new Account(100, "结婚基金");
    
            Drawing jay = new Drawing(account, 50, "jay");
            Drawing kelly = new Drawing(account, 100, "kelly");
    
            jay.start();
            kelly.start();
        }
    }
    
    
    //账户
    class Account {
        int money;  //余额
        String name;  //卡名
    
        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    }
    
    //银行:模拟取款
    class Drawing extends Thread {
    
        Account account;   //账户
        int drawingMoney;  //取了多少钱
        int nowMoney;  //手上的钱
    
        //构造器
        public Drawing(Account account, int drawingMoney, String name) {
            super(name);
            this.account = account;
            this.drawingMoney = drawingMoney;
        }
    
        //取钱
        @Override
        public void run() {
            //判断余额
            if (account.money-drawingMoney<0) {
                System.out.println(Thread.currentThread().getName()+"钱不够了!");
                return;
            }
            //模拟延迟 放大问题的发生性
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            //卡内余额 = 余额 - 取的钱
            account.money -= drawingMoney;
            nowMoney += drawingMoney;
    
            //你卡里的钱
            System.out.println(account.name+"余额为:"+account.money);
            //你手里的钱
            System.out.println(this.getName()+"手里的钱为:"+nowMoney);
        }
    }
    
    /*
    结婚基金余额为:50
    结婚基金余额为:-50
    jay手里的钱为:50
    kelly手里的钱为:100
     */
    
    package com.guanxing.syn;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class UnsafeList {
        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();
            for (int i = 0; i < 10000; i++) {
                new Thread(()->{
                    list.add(Thread.currentThread().getName());
                }).start();
            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(list.size());  //9617 没有sleep  sleep5s 9999
        }
    }
    

    死锁

    某一个同步块同时拥有 “ 两个以上对象的锁 ” 时,就可能发生 “ 死锁 ” 现象。

    两个或多个线程都在等待对方释放资源,都停止运行的情况

    产生死锁的四个必要条件(想办法打破一个就可避免!)

    • 互斥条件:一个资源每次只能被一个进程使用
    • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
    • 不剥夺条件:进程已获得的资源,在未使用完之前,不能抢行剥夺
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
    package com.guanxing.syn;
    
    //死锁:多个线程互相抱着对方需要的资源,形成僵持
    public class DeadLock {
        public static void main(String[] args) {
            Makeup joey = new Makeup(0, "joey");
            Makeup kane = new Makeup(1, "kane");
            joey.start();
            kane.start();
        }
    }
    
    //口红
    class Lipstick {
    }
    
    //镜子
    class Mirror {
    }
    
    class Makeup extends Thread {
        //口红和镜子(static保证都只有一个)
        static Lipstick lipstick = new Lipstick();
        static Mirror mirror = new Mirror();
    
        //化妆者的选择和名字
        int choice;
        String girlName;
    
        //构造器
        public 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) {//抱着口红的锁想获得镜子的锁
                        System.out.println(this.girlName+"抢到镜子了!");
                    }
                }
            } else {
                synchronized (mirror) {
                    System.out.println(this.girlName+"抢到镜子!");
                    Thread.sleep(2000);
                    synchronized (lipstick) {
                        System.out.println(this.girlName+"抢到口红了!");
                    }
                }
            }
        }
    }
    

    解决方法:同时只能拿着一把锁

    //化妆的方法,互相持有对方的资源
    private void makeup() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {//获得口红的锁
                System.out.println(this.girlName+"抢到口红!");
                Thread.sleep(1000);
            }
            synchronized (mirror) {//抱着口红的锁想获得镜子的锁
                System.out.println(this.girlName+"抢到镜子了!");
            }
        } else {
            synchronized (mirror) {
                System.out.println(this.girlName+"抢到镜子!");
                Thread.sleep(2000);
            }
            synchronized (lipstick) {
                System.out.println(this.girlName+"抢到口红了!");
            }
        }
    }
    

    Lock(锁)

    显示定义同步锁对象来实现同步,手动开启和关闭锁

    java.util.concurrent.locks.Lock 接口是控制多个线程对共享资源进行访问的工具

    ReentrantLock 类实现了 Lock(re-entrant 可重入锁)

    Lock只有代码块锁,syn有代码块锁和方法锁

    package com.guanxing.syn;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    //测试Lock锁
    public class TestLock {
        public static void main(String[] args) {
            MyLock myLock = new MyLock();
    
            new Thread(myLock).start();
            new Thread(myLock).start();
            new Thread(myLock).start();
        }
    }
    
    class MyLock implements Runnable {
        //票
        int ticketNum = 1000;
        //定义Lock锁
        private final ReentrantLock lock = new ReentrantLock();
    
        @Override
        public void run() {
            while (true) {
                try {
                    lock.lock(); //加锁
                    if (ticketNum>0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()+"-->"+ticketNum--);
                    }else {
                        break;
                    }
                }finally {
                    //解锁
                    lock.unlock();
                }
    
            }
        }
    }
    
  • 相关阅读:
    Python网络爬虫 第三章 requests进阶
    Python网络爬虫 第二章 数据解析
    Java 工具库Hutool-db数据库简单操作
    JavaScript基础
    K-Means文档聚类
    利用余弦距离比较文档间的相似度
    算法类——数学问题汇总
    基于K-Means的文本聚类
    加速国内 Github 访问,下载,的9种方案!
    为什么用MQTT而不用TCP长连接透传
  • 原文地址:https://www.cnblogs.com/straightup/p/14503477.html
Copyright © 2020-2023  润新知