多线程的学习:day6 线程同步(多线程的重点和难点)

本文探讨了线程同步在并发编程中的重要性,通过卖票类实例说明了未加锁可能导致的数据紊乱和死锁问题,以及使用synchronized关键字进行锁管理的必要性和潜在问题。
摘要由CSDN通过智能技术生成

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

所以线程同步也有另外一种广为人知的叫法:并发!!!!!!!!!

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

我们首先要知道:每一个对象都有一把

举个例子说明:现实生活中,我们会遇到”同一个资源,多个人都想使用”的问题,比如,食堂排队打饭,每个人都想吃饭,最天然的解决办法就是,排队.一个个来

在实际的线程编程之中我们会遇到,多个线程访问同一个对象,并且某些线程还想修改这个对象这时候我们就需要线程同步.线程同步其实就是一种等待机制多个需要同时访问此对象的线程进入这个对象的等待池 形成队列,等待前面线程使用完毕,下一个线程再使用

由上面所述,并发要形成的条件就是队列+锁

那么如何让并发开启呢?只需要在某个线程访问时加入机制synchronized(关键字),当一个线程获得对象的排它锁,独占资源,其他线程必须等待使用后释放锁即可。但存在以下问题

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

简而言之就是:线程用了锁(synchronized)就会牺牲掉业务执行的性能,但保证了数据的稳定运输不紊乱。与之相反的是:如果有很多线程,但不使用锁(synchronized),虽然有了性能,但是数据会发生紊乱,不安全。

下面举例说明不安全的情况

6.1创建 一个卖票的类实现Runnable接口——>既然卖票就需要有“票”这个变量——>既然是有动作发生那么我们需要标志位变量让其能停止——>可拆写一个卖票的方法,然后在run()方法里面运行它

 implements Runnable{
//    Scanner in = new Scanner(System.in);
    //票,先写变狼
    private int ticket =10;
    boolean flag = true; // 外部停止方式
    @Override
    public void run() {
        while (flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    void buy() throws InterruptedException {
        if (ticket <= 0) {
            flag = false;
            return;
        }
        //模拟延时
        Thread.sleep(100);
        //买票,
        System.out.println(Thread.currentThread().getName() + "拿到第" + ticket-- + "票");
    }
}

6.2 创建一个main类,引入实现Runnable接口的类的对象,并创建几个线程,模拟多人购票的场景,里面里面传入name变量是因为使用了:Thread.currentThread().getName()

//不安全的买票
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        //先把子线程的对象new 出来
        BuyTicket station = new BuyTicket();
        //然后写子线程的启动
        new Thread(station,"小谢").start(); //第一条子线程
        new Thread(station,"蜡笔").start(); //第二条子线程
        new Thread(station,"小新").start(); //第三条子线程

    }

}

结果分析

因为没有给被多个线程执行的资源(在这个代码里面就是“票”)加锁,所以出现了有人买到第0票的结果和多人买到同一张票的结果

6.3修改,在run()方法之中加入标识符 synchronized

class BuyTicket implements Runnable {
    private int ticket = 10;
    boolean flag = true;

    @Override
    public synchronized void run() {  //这里加入synchronized
        while (flag) {
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

   synchronized void buy() throws InterruptedException {
        if (ticket <= 0) {
            flag = false;
            return;
        }
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName() + "拿到第" + ticket-- + "票");
    }
}

第二个结果分析

由于对执行操作的方法添加了锁的标识符,所以结果没有溢出,但却造成了死锁的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值