07_并发、同步、安全

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

线程同步

队列 + 锁 = 同步

为保证数据在方法中被访问的正确性,在访问时加入锁机制,当一个线程获得资源的访问权时,会加上排他锁,独占资源,其他线程必须等待,使用后释放锁即可

但是就存在一些问题:

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

在并发时保证数据的准确性,并且效率尽可能高

synchronized

两种用法:

  1. synchronized方法
  2. synchronized块

缺陷:

若将一个大方法声明为synchronized会大大影响效率

synchronized方法
package com.tsymq.thread.concurrnet;

public class Safe implements Runnable {
    // 票数
    private int tickets = 1000;
    private boolean flag = true;

    @Override
    public void run() {
        while (flag) {
            qiangpiao();
        }
    }

    private synchronized void qiangpiao(){
        if (tickets <= 0) {
            flag = false;
            return;
        }
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        tickets--;
        System.out.println(Thread.currentThread().getName() + "抢票,剩余票数:" + tickets);
    }

    public static void main(String[] args) {
        System.out.println("main线程开启");

        Safe huangniu = new Safe();

        new Thread(huangniu, "携程").start();
        new Thread(huangniu, "美团").start();
        new Thread(huangniu, "去哪儿").start();

    }
}
synchronized块

java中4种块:

  • 普通块局部块
  • class构造块
  • 静态块
  • 同步块
package com.tsymq.thread.concurrnet;

public class SafeDrawing {
    public static void main(String[] args) {
        // 账户
        Account account = new Account(170, "礼金");
        Drawing you = new Drawing(account, 80, "你");
        Drawing she = new Drawing(account, 90, "她");
        you.start();
        she.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 packetTotal;    // 口袋余额

    public Drawing(Account account, int drawingMoney, String name){
        super(name);
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    @Override
    public void run() {
        drawing();
    }

    private void drawing() {
        if(account.money <= 0){
            return;
        }
        // 应锁定account对象
        synchronized (account){
            if (account.money - drawingMoney < 0){
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money -= drawingMoney;
            packetTotal += drawingMoney;
            System.out.println(this.getName() + "账户余额:" + account.money);
            System.out.println(this.getName() + "口袋余额:" + packetTotal);
        }
    }
}

使用synchronized块时一定要锁对东西,要锁的是一个不变的对象,对象在变和对象的属性在变是不一样的,而且要尽可能锁定合理的范围(不是代码的多少,是数据的完整性)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值