线程安全~

文章介绍了线性安全问题的概念,即在多线程环境下操作共享资源可能导致的安全隐患。通过共同账户取钱的例子展示了线程安全问题,并提出了三种解决线程安全的方法:同步代码块、同步方法和使用Lock锁。同步代码块和同步方法基于内置锁实现,而Lock锁提供了更细粒度的控制。

什么是线性安全问题

多个线程同时操作同一个共享资源的时候可以会出现业务安全问题,称为线程安全问题
出现原因:1.存在多线程并发 2.同时访问共享资源 3.存在修改共享资源
在这里插入图片描述

共同账户取钱问题(存在线程安全问题)

public class ATMTest {
    public static void main(String[] args)throws Exception {
        //共同账户
        Account account = new Account();
        FutureTask f1 = new FutureTask(new Get(account));
        Thread thread1 = new Thread(f1);
        FutureTask f2 = new FutureTask(new Get(account));
        Thread thread2 = new Thread(f2);
        thread1.start();
        thread2.start();
        System.out.println((Integer) f1.get());
        System.out.println((Integer) f2.get());
        System.out.println(account.getAnInt());


    }
}

@Getter
@Setter
class Account{
    private Integer anInt = 10000;

    public Integer getMoney(int i){
        if (anInt>i){
            anInt = anInt - i;
            return i;
        }else {
            System.out.println("余额不足");
            return null;
        }
    }
}

class Get implements Callable<Integer>{

    private Account account;

    public Get(Account account) {
        this.account = account;
    }

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"输入您要取的钱数:");
        int i = new Scanner(System.in).nextInt();
        return account.getMoney(i);
    }
}

线程同步

为了解决线程安全问题
让多个线程依次访问共享资源,解决安全问题
线程同步的核心思想:
加锁,把共享资源上锁,每次只能一个进程进入访问完毕以后解锁,然后其他线程才能进来

方式一:同步代码块

在这里插入图片描述

public class ATMTest {
    public static void main(String[] args)throws Exception {
        //共同账户
        Account account = new Account();
        FutureTask f1 = new FutureTask(new Get(account));
        Thread thread1 = new Thread(f1);
        FutureTask f2 = new FutureTask(new Get(account));
        Thread thread2 = new Thread(f2);
        thread1.start();
        thread2.start();
        System.out.println((Integer) f1.get());
        System.out.println((Integer) f2.get());
        System.out.println(account.getAnInt());


    }
}

@Getter
@Setter
class Account{
    private Integer anInt = 10000;

    public Integer getMoney(int i){
        synchronized ("ccc") {
            if (anInt>i){
                anInt = anInt - i;
                return i;
            }else {
                System.out.println("余额不足");
                return null;
            }
        }
    }
}

class Get implements Callable<Integer>{

    private Account account;

    public Get(Account account) {
        this.account = account;
    }

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"输入您要取的钱数:");
        int i = new Scanner(System.in).nextInt();
        return account.getMoney(i);
    }
}

锁对象不能用任意的无关对象,不然会影响其他无关进程的执行
锁对象的规范要求:
规范上:建议使用共享资源作为锁对象
对于实例方法建议使用this作为锁对象
对于静态方法建议使用字节码(类名.class)对象作为锁对象(因为静态方法在内存中是唯一的,所以直接使用类名上锁)

方式二:同步方法

在这里插入图片描述

在这里插入图片描述

方式三:Lock锁

在这里插入图片描述

public class ATMTest {
    public static void main(String[] args)throws Exception {
        //共同账户
        Account account = new Account();
        FutureTask f1 = new FutureTask(new Get(account));
        Thread thread1 = new Thread(f1);
        FutureTask f2 = new FutureTask(new Get(account));
        Thread thread2 = new Thread(f2);
        thread1.start();
        thread2.start();
        System.out.println((Integer) f1.get());
        System.out.println((Integer) f2.get());
        System.out.println(account.getAnInt());


    }
}

@Getter
@Setter
class Account{
    private Integer anInt = 10000;
    private final Lock lock =new ReentrantLock(); //锁对象,唯一,不可修改

    public Integer getMoney(int i){
        lock.lock();
        try {
            if (anInt>i){
                anInt = anInt - i;
                return i;
            }else {
                System.out.println("余额不足");
                return null;
            }
        } finally {
            lock.unlock();
        }
    }
}


class Get implements Callable<Integer>{

    private Account account;

    public Get(Account account) {
        this.account = account;
    }

    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+"输入您要取的钱数:");
        int i = new Scanner(System.in).nextInt();
        return account.getMoney(i);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值