线程同步机制和三个线程不安全例子
发布日期:2021-05-08 02:59:33 浏览次数:10 分类:精选文章

本文共 3567 字,大约阅读时间需要 11 分钟。

并发: 同一个对象被多个线程同时操作;

1.由于同一进程的多个线程共享同一块存储空间,会发生访问冲突问题.为了访问的正确性,在访问时加入了锁机制(synchronized) 。当一个线程获得对象的排它锁时,独占资源,其他线程必须等待,使用后释放锁即可。

2.一个线程持有锁会导致其他所有需要此锁的线程挂起;
3.在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;
4.如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题

1.抢票不安全问题

//多个线程处理同一资源时,线程不安全会出现数据紊乱public class UnsafeBuyTicket {       public static void main(String[] args) {          Myticket myticket = new Myticket();       new Thread(myticket,"用户1").start();       new Thread(myticket,"用户2").start();       new Thread(myticket,"用户3").start();    }}//买票的类class Myticket implements Runnable{       private int tickets = 10;//设置总票数      boolean flag = true;//采用外部停止的方式          @Override    public void run() {   //run()方法的作用是票未抢完时,不断更新抢票的状态        //买票        while (flag){               try {                   buy();            } catch (InterruptedException e) {                   e.printStackTrace();            }        }    }    //判断是否有票    private void buy() throws InterruptedException {           while (flag){               if(tickets<=0) {                   flag = false;                return;            }            //模拟延时            Thread.sleep(100);        System.out.println(Thread.currentThread().getName()+"抢到了第"+tickets--+"张票");}    }

抢票结果会出现负数,线程不安全

在这里插入图片描述
2.同时取钱不安全
实现思路:
1.先创建账户,包含账户名字余额两个变量,为实现接收输入-构造器
2创建取款类并继承Thread类,银行取款流程:账户信息+取款金额+判断余额是否大于取款金额,实现多个线程同时取款继承Thread类-重写run()方法
3.在main()方法要给Thread类中传递名字,在Thread的子类构造器第一行调用super(name);
4.在run()方法中具体实现余额判断更新

//不安全事件//模拟银行取钱public class UnsafaBank {       public static void main(String[] args) {         Account account = new Account(100,"卡内");        Drawing drawing01 = new Drawing(account,50,"用户1");        Drawing drawing02 = new Drawing(account,100,"用户2");        drawing01.start();        drawing02.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 = account.money-drawingmoney;        //手里的钱        nowmoney = nowmoney+drawingmoney;        //输出账户的钱        System.out.println(account.name+"余额为:"+account.money);        //输出用户拿到的钱        System.out.println(Thread.currentThread().getName()+"取出"+nowmoney);    }}

线程不安全,两个线程同时对一个资源操作时,出现余额为负数

在这里插入图片描述
3.线程不安全
List是Java中比较常用的集合类,关于List接口有很多实现类,其中几个重点的实现是ArrayList、LinkedList和Vector

//线程不安全public class UnsafeList {       public static void main(String[] args) {          List
list = new ArrayList
(); for (int i = 0; i < 10000; i++) { //同时创建10000个线性,使用Lambda new Thread(()->{ list.add(Thread.currentThread().getName()); }).start(); } try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(list.size()); }}

在这里插入图片描述

之所以list集合没有10000个元素,有可能多个线程同时将线程名加入列表导致覆盖

上一篇:同步方法和同步块
下一篇:守护线程

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年03月19日 05时59分19秒