0
点赞
收藏
分享

微信扫一扫

学习博客:并发初步了解

并发:同一个对象被多个线程同时操作(抢票)

每个对象都有一把锁,sleep不会释放锁

线程同步:多个线程操作同一个资源

线程同步的条件:队列和锁(安全性高,但会损失性能)
例子:队列(排队上厕所)和锁(为保证安全,一次只能有一个上厕所)

同一进程的多个线程共享同一块存储空间,使用方便,但会带来访问冲突,锁机制(synchronized)可保证数据在方法中被访问时的正确性。当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁,此时会存在问题

synchronized关键字两种用法

不安全的买票案例

//线程不安全
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();

        new Thread(station, "学生").start();
        new Thread(station, "老师").start();
        new Thread(station, "公务员").start();

    }
}

class BuyTicket implements Runnable{

    //票
    private int ticketNums = 100;

    boolean flag = true;    //停止方式

    //买票
    @Override
    public void run() {
        //买票
        while(flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void buy() throws InterruptedException {
        //判断是否有票
        if(ticketNums <= 0){
            flag = false;
            return;
        }

        //模拟延时
        Thread.sleep(1000);

        //买票
        System.out.println(Thread.currentThread().getName() + "拿到" + ticketNums--);
    }
}

在这里插入图片描述同一张票会被多人抢到,说明线程是不安全的
添加同步锁后

    private synchronized void buy() throws InterruptedException {
        //判断是否有票
        if(ticketNums <= 0){
            flag = false;
            return;
        }

在这里插入图片描述
同一张票只能被一个人拿到

不安全的取款案例

public class UnsafeBank {
    public static void main(String[] args) {
        //账户
        Account account = new Account(100,"教育基金");

        Drawing me = new Drawing(account, 80, "我");
        Drawing you = new Drawing(account, 70, "你");

        me.start();
        you.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(this.getName() + "现有:" + nowMoney);

    }
}

在这里插入图片描述
银行账户出现负数,当两个线程同时看到账户余额足够取的时候,都将自己需要的数字拿到了自己的内存里,此时线程是不安全的
为账户account添加同步锁后

synchronized (account) {
            //判断是否有钱
            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(this.getName() + "现有:" + nowMoney);
        }

在这里插入图片描述

线程不安全的集合

//线程不安全的集合
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                    list.add(Thread.currentThread().getName());
            }).start();
        }

        Thread.sleep(1000);

        System.out.println(list.size());

    }
}

在这里插入图片描述
10000个线程没有被全部添加,在添加过程中,会出现集合的某个位置同时添加两个线程的情况,后来的线程被覆盖掉了,少的这8个其实是被覆盖掉了

            synchronized (list) {
                list.add(Thread.currentThread().getName());
            }

在这里插入图片描述

扩展

import java.util.concurrent.CopyOnWriteArrayList;

//测试JUC安全类型的集合
public class TestJUC {
    public static void main(String[] args) throws InterruptedException {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(() -> {
                list.add(Thread.currentThread().getName());
            }).start();
        }

        Thread.sleep(1000);
        System.out.println(list.size());
    }
}

在这里插入图片描述

举报

相关推荐

JS初步了解this

初步了解java

docker初步了解

HTML初步了解

FFmpeg初步了解

0 条评论