美文网首页
多线程-线程安全

多线程-线程安全

作者: 无力韬韬 | 来源:发表于2020-11-29 22:26 被阅读0次

非线程安全

public class SafeThread {
    public static void main(String[] args) {
        Safe12306 t=new Safe12306(100);
        Thread thread1=new Thread(t,"小红");
        Thread thread2=new Thread(t,"小白");
        Thread thread3=new Thread(t,"小黑");
        thread1.start();
        thread2.start();
        thread3.start();
    }

}
class Safe12306 implements Runnable
{
    private Integer tickets;
    private boolean flag=true;

    public Safe12306(Integer tickets) {
        this.tickets = tickets;
    }

    @Override
    public void run() {
    while (flag)
    {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        BuyTicket();
    }
    }

    private void BuyTicket() {
        if (tickets<=0)
        {
            flag=false;
            return;
        }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+" --> Ticket"+tickets--);
    }
}

模拟了延时之后,可能会出现多个人买到同一张票或者有人买到了不存在的票的情况。


结果
结果

这就是线程不安全的情况。
为什么会出现这两种情况,首先看有人买到不存在的票的情况,当只有最后一张票的时候,小黑小红小白三人都进入了BuyTicket方法此时TICKET=1,此时执行sleep方法,模拟网络延迟,小黑先进入先sleep,到了小红小红也sleep,然后小白也sleep,然后小黑重新被分配CPU获得最后一票,而小红和小白只能获得不存在的票。
多人买到同一张票的情况,线程的机制是从主存中复制数据到自己的工作区,然后再把自己更改过的内容覆盖到主存,多人买到同一张票应该是小黑复制到了自己的工作区还没有覆盖主存,小红和小白就已经复制主存中的内容到自己的工作区。

线程安全

  • 实现线程同步
    1.同步方法
    给BuyTicket方法加上synchronized关键字。
private synchronized void BuyTicket() {

        try {
            Thread.sleep(400);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (tickets<=0)
        {
            flag=false;
            return;
        }
        System.out.println(Thread.currentThread().getName()+" --> Ticket"+tickets--);
    }

synchronized看似锁的是方法实际是当前对象(this)。更改了哪个对象的内容就要锁哪个对象,锁方法的开销较大,一般不推荐锁方法。
2.同步代码块

public class SafeFrame {
  public static void main(String[] args) {
      HashMap <String ,Integer> map=new HashMap<>();
      ConcurrentHashMap<String ,Integer>cmap=new ConcurrentHashMap<>();
      LinkedList<String> list=new LinkedList<>();
      for (int i=0;i<10000;i++)
      {
          int finalI = i;
          new Thread(()->{
              list.add(Thread.currentThread().getName());
              synchronized (map){
                  map.put(Thread.currentThread().getName(), finalI);
              }
              cmap.put(Thread.currentThread().getName(),finalI);
          }).start();
      }
      try {
          Thread.sleep(1000);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
      System.out.println("list==>"+list.size());
      System.out.println("hashmap==>"+map.size());
      System.out.println("concurrenthashmap==>"+cmap.size());

  }
}
结果

syncchronized锁了map,结果输出和本来就是ConcurrentHashMap一样,但是List输出结果不正确。
取钱操作

public class SafeBank {
    public static void main(String[] args) {
        Account tt=new Account("TT",100);
        Draw xx=new Draw(tt,90,"xx");
        Draw t=new Draw(tt,30,"tt");
        Thread thread1=new Thread(t);
        Thread thread2=new Thread(xx);
        thread1.start();
        thread2.start();
    }
}
class Account
{
    String name;
    Integer money;

    public Account(String name, Integer money) {
        this.name = name;
        this.money = money;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }
}
class Draw implements Runnable
{
    Account account;
    Integer pocketmoney;
    String pocketName;
    public Draw(Account account, Integer pocketmoney,String pocketName) {
        this.account = account;
        this.pocketmoney = pocketmoney;
        this.pocketName=pocketName;
    }

    @Override
    public void run() {
        if(account.money-pocketmoney<=0)
        {
            System.out.println("没钱");
            return;
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.setMoney(account.money-pocketmoney);
        System.out.println(pocketName+"取走了"+account.name+pocketmoney+"元,还剩"+account.money+"元");
    }
}

如果不加同步就会出现余额为负数的情况


结果

这时候需要加Synchronized,但是要注意,此时需要操作的对象是Account而不是this,所以不能在run方法上加锁,应该使用synchronized代码块。

public void run() {

        synchronized (account)
        {
            if(account.money-pocketmoney<=0)
            {
            System.out.println("没钱");
            return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.setMoney(account.money-pocketmoney);
            System.out.println(pocketName+"取走了"+account.name+pocketmoney+"元,还剩"+account.money+"元");
        }

    }
结果

相关文章

  • 线程安全知多少

    1. 如何定义线程安全 线程安全,拆开来看: 线程:指多线程的应用场景下。 安全:指数据安全。 多线程就不用过多介...

  • 2018-05-08

    多线程 初级概念与传参 join deatch 原子变量 互斥锁 与 线程安全 线程安全 多线程访问冲突 冲突...

  • iOS关于property中的atomic和nonatomic

    首先这两个属性特质是为了处理多线程安全问题,那么什么是多线程安全,多线程安全就是多个线程访问同一段代码、指针区域、...

  • ConcurrentHashMap

    总结 HashMap在多线程中不安全,java提供了线程安全的ConcurrentHashMap 类,保证在多线程...

  • HashMap相关

    HashMap是数组+链表 1.HashMap不是线程安全,为什么不是线程安全的呢? 多线程put,多线程reha...

  • 几个小问题

    1、FMDB与多线程 SQLITE默认的线程模式是串行模式, 是线程安全的FMDatabase多线程不安全, 单个...

  • iOS多线程到底不安全在哪里?

    iOS多线程到底不安全在哪里? iOS多线程到底不安全在哪里?

  • 多线程学习笔记

    多线程出现目的 如何使用多线程 线程状态(6种) 线程开启/停止 线程安全VolilateSychronized机...

  • 后端架构师技术图谱(三)-并发、锁、设计模式(二)

    并发 多线程 《40个Java多线程问题总结》 线程安全 《Java并发编程——线程安全及解决机制简介》 一致性、...

  • Java多线程

    目录 什么是多线程?引入多线程的意义何在? 并行和并发 线程安全 线程状态 如何保证线程安全? 创建线程的三种方法...

网友评论

      本文标题:多线程-线程安全

      本文链接:https://www.haomeiwen.com/subject/wkzusktx.html