多线程学习笔记---(线程不安全问题)

线程不安全问题
取钱问题
  • 账户余额是100,两个人都要取100,两个人在取之前都获取到余额是100,可以继续往下取,第一个人取完了,余额变为0,第二个人继续取,余额变成负数;或者两个人都获取到100,在取的时候也是100,使得两个人都取过之后最新的余额为0
public class BuyTicket {
    public static void main(String[] args) {
        People lily = new People("lily", 0);
        People benjen = new People("benjen", 0);
        Account wedding = new Account("wedding",10 );
        new bank(lily,wedding).start();
        new bank(benjen,wedding).start();
    }
}
class Account{
    String account;
    int balance;

    public Account(String account, int balance) {
        this.account = account;
        this.balance = balance;
    }
}
class People{
    String name;
    int money;

    public People(String name, int money) {
        this.name = name;
        this.money = money;
    }
}

class bank extends Thread{
    People people;
    Account account;

    public bank(People people, Account account) {
        this.people = people;
        this.account = account;
    }

    public void draw(int i){
        if (account.balance<i){
            System.out.println("balance is not enough");
            return;
        }
        account.balance=account.balance-i;
        people.money=i+people.money;
        System.out.println(people.name+" now has "+people.money);
        System.out.println(account.account+ "now has "+account.balance);
        System.out.println("________________");
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            draw(1);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

买票问题
  • 多个线程同时卖票,同时获取到票为10张,还可以卖,第一个线程卖出去了,第二个线程再卖一张就导致了多卖票
public class SellTickets {
    public static void main(String[] args) {
        Station station = new Station();
        Thread t1 = new Thread(station);
        Thread t2 = new Thread(station);
        Thread t3 = new Thread(station);
        t1.start();
        t2.start();
        t3.start();
    }
}
class Station implements Runnable{
    int num=0;
    @Override
    public void run() {
        while (num<11){
            System.out.println("sell "+(++num)+" tickets");
        }
    }
}
  • 数组的不安全问题,这篇文章写得比较清楚:https://segmentfault.com/a/1190000023807751
  1. ArrayList的默认大小是10,当大小为9时,两个线程同时添加元素,第一个添加完后,数组已经满了,第二个再添加导致越界
  2. 两个数组同时在同一个位置添加元素,然后依次对size加1,导致一个元素被覆盖,后一个元素为null
  3. 连个数组同时在同一个位置添加元素,获取到相同的size并加1,使得size最终只加了一个1,使得数组大小小于预期
  4. CopyOnWriteArrayList不存在这个问题

public class ListUnSafe {
    public static void main(String[] args) {
        ArrayList<String> strings = new ArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    strings.add(Thread.currentThread().getName());
                    try {
                        Thread.sleep(900);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

        }

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(strings.size());
    }
}

synchronized关键字
  • 多个线程访问甚至修改同一个对象,这种现象叫并发;这种情况需要线程同步,即让同时访问的线程进入等待池等待资源被正在访问的线程释放。
  • 可以加入synchronized关键字来对资源进行加锁,下面这篇笔记讲得比较清楚

https://www.cnblogs.com/mengdd/archive/2013/02/16/2913806.html
1 修饰一个普通方法,是对象锁,同一个对象中所有被synchronized修饰的普通方法使用的均是同一把对象锁,等同于synchronized(this){代码块};当使用thread来创建线程时,由于this不是同一个对象,方法锁会无效
2 修饰一个代码块,也是对象锁。括号内可以填任意对象。若两个代码块括号内的对象相同,则上的是同一把对象锁,无法被同一个对象访问;若括号内的对象不同,可以被同一个对象使用。(若括号内的对象是string类型,并且这个string对象会在访问过程中被重新赋值,说明这个对象一直在变,无法保证一直是同一把锁,这里涉及到string的内存问题,可以参考:https://isudox.com/2016/06/22/memory-model-of-string-in-java-language/)
3 修饰一个静态方法,使用的是类锁,所有的对象都无法同时访问上了类锁的方法。类锁和对象锁不冲突,即使是同一个对象,也可以在访问类锁方法的时候访问对象锁。

ReentrantLock
  • 好处是可以主动解锁
  • 但是只能对代码块加锁
生产者消费者问题
  • 这篇文章写得比较清楚
  • notify和signal都只会随机唤醒一个线程,可能唤醒的不是目标线程,被唤醒的目标线程又重新wait,使得所有线程wait,导致死锁。
  • 可以通过notifyAll和signalAll简单粗暴地唤醒所有的线程。
  • 更好的方法是建立针对性的condition 来针对性地唤醒线程
    https://www.jianshu.com/p/d3214bd34a2d
死锁

两个线程都占用一部分资源,并且都在等待对方释放资源,产生死锁

public class DeadLock {
    public static void main(String[] args) {
        eat eat = new eat();
        drink drink = new drink();
        new table(0,eat,drink).start();
        new table(1,eat,drink).start();
    }
}

class eat{}
class drink{}

class table extends Thread{
    int choice;
    eat eat;
    drink drink;

    public table(int choice, com.citi.threadtest.eat eat, com.citi.threadtest.drink drink) {
        this.choice = choice;
        this.eat = eat;
        this.drink = drink;
    }

    @Override
    public void run() {
        if (choice==0){
            synchronized (eat){
                System.out.println("0-eat");
                synchronized (drink){
                    System.out.println("0-drink");
                }
            }
        }else if (choice==1){
            synchronized (drink){
                System.out.println("1-drink");
                synchronized (eat){
                    System.out.println("1-eat");
                }
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码下载:完整代码,可直接运行 ;运行版本:2022a或2019b或2014a;若运行有问题,可私信博主; **仿真咨询 1 各类智能优化算法改进及应用** 生产调度、经济调度、装配线调度、充电优化、车间调度、发车优化、水库调度、三维装箱、物流选址、货位优化、公交排班优化、充电桩布局优化、车间布局优化、集装箱船配载优化、水泵组合优化、解医疗资源分配优化、设施布局优化、可视域基站和无人机选址优化 **2 机器学习和深度学习方面** 卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM、XGBOOST、TCN实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 **3 图像处理方面** 图像识别、图像分割、图像检测、图像隐藏、图像配准、图像拼接、图像融合、图像增强、图像压缩感知 **4 路径规划方面** 旅行商问题(TSP)、车辆路径问题(VRP、MVRP、CVRP、VRPTW等)、无人机三维路径规划、无人机协同、无人机编队、机器人路径规划、栅格地图路径规划、多式联运运输问题、车辆协同无人机路径规划、天线线性阵列分布优化、车间布局优化 **5 无人机应用方面** 无人机路径规划、无人机控制、无人机编队、无人机协同、无人机任务分配 **6 无线传感器定位及布局方面** 传感器部署优化、通信协议优化、路由优化、目标定位优化、Dv-Hop定位优化、Leach协议优化、WSN覆盖优化、组播优化、RSSI定位优化 **7 信号处理方面** 信号识别、信号加密、信号去噪、信号增强、雷达信号处理、信号水印嵌入提取、肌电信号、脑电信号、信号配时优化 **8 电力系统方面** 微电网优化、无功优化、配电网重构、储能配置 **9 元胞自动机方面** 交通流 人群疏散 病毒扩散 晶体生长 **10 雷达方面** 卡尔曼滤波跟踪、航迹关联、航迹融合

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值