线程安全 -(一)同步代码块

本人所有文章,只属学习整理及个人理解!有误还望谅解并指出,谢谢!持续更新中…

线程同步

  • 问题描述:
    当我们使用多个线程访问同一资源的时候,且多个线程中对资源有写操作,就容易出现线程安全问题。

  • 解决方案:
    要解决上述多线程并发访问一个资源的安全性问题;也就是解决重复票不不存在票的问题,Java中提供了同步机制(synchronized)来解决。

为了保证每个线程都能正常执行原子操作,Java引入了线程同步机制。

实现线程同步的三种方式:

一、同步代码块。

同样是卖票案例,小二上代码:

/**
 * 卖票案例 出现了线程安全问题;
 * 卖出了不存在和相同的票
 * 1、使用同步代码块
 * 格式:
 *  synchronized(锁对象){
 *      可能会出现线程安全问题的代码(访问了共享数据的代码)
 *  }
 *  注意:
 *  1、通过代码块中的锁对象,可以使用任意的对象
 *  2、但是必须保证多个线程使用的锁对象是同一个
 *  3、锁对象作用:
 *      把同步代码块给锁住,只让一个线程在同步代码块中执行
 *
 */
public class RunnableImpl implements Runnable {

    // 定义一个多线程共享的票源
    private int ticket = 100;


    //创建一个锁对象,且所有线程得到的是同一个对象锁,所以只能在run方法外部去创建
    Object obj = new Object();


    // 设置线程任务:开始买票
    @Override
    public void run() {

        // 设置不停的买票
        while (true) {


            // 同步代码块
            synchronized (obj) {


                // 判断票是否存在
                if (ticket > 0) {

                    // 票存在,买票 ticket--
                    System.out.println(Thread.currentThread().getName()+"--->正在卖第"+ticket+"张票");

                    // 卖出去一张,ticket 递减
                    ticket--;
                }


            }


        }

    }
}

小二卖票的窗口一同给开了吧:

public class TicketTest {

    public static void main(String[] args) {

        // 创建 Runnable 接口的实现类对象
        Runnable r1 = new RunnableImpl();

        // 创建 Thread 类对象,构造方法中传递 Runnable 接口的实现对象
        Thread t0 = new Thread(r1);
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r1);

        // 调用 start 方法 开启多线程
        t0.start();
        t1.start();
        t2.start();
        
        /*
            Thread-0--->正在卖第100张票
            Thread-0--->正在卖第99张票
            Thread-2--->正在卖第98张票
            Thread-2--->正在卖第97张票
            Thread-2--->正在卖第96张票
            Thread-2--->正在卖第95张票
            Thread-2--->正在卖第94张票
            Thread-1--->正在卖第93张票
            Thread-1--->正在卖第92张票
            Thread-1--->正在卖第91张票
            Thread-1--->正在卖第90张票
            Thread-1--->正在卖第89张票
            Thread-1--->正在卖第88张票
            Thread-1--->正在卖第87张票
            Thread-1--->正在卖第86张票
            Thread-1--->正在卖第85张票
            Thread-1--->正在卖第84张票
            Thread-1--->正在卖第83张票
            Thread-1--->正在卖第82张票
            Thread-1--->正在卖第81张票
            Thread-1--->正在卖第80张票
            Thread-1--->正在卖第79张票
            Thread-1--->正在卖第78张票
            Thread-1--->正在卖第77张票
            Thread-1--->正在卖第76张票
            Thread-1--->正在卖第75张票
            Thread-1--->正在卖第74张票
            Thread-1--->正在卖第73张票
            Thread-1--->正在卖第72张票
            Thread-1--->正在卖第71张票
            Thread-1--->正在卖第70张票
            Thread-1--->正在卖第69张票
            Thread-1--->正在卖第68张票
            Thread-1--->正在卖第67张票
            Thread-1--->正在卖第66张票
            Thread-2--->正在卖第65张票
            Thread-2--->正在卖第64张票
            Thread-2--->正在卖第63张票
            Thread-2--->正在卖第62张票
            Thread-2--->正在卖第61张票
            Thread-2--->正在卖第60张票
            Thread-2--->正在卖第59张票
            Thread-2--->正在卖第58张票
            Thread-2--->正在卖第57张票
            Thread-2--->正在卖第56张票
            Thread-2--->正在卖第55张票
            Thread-2--->正在卖第54张票
            Thread-2--->正在卖第53张票
            Thread-2--->正在卖第52张票
            Thread-2--->正在卖第51张票
            Thread-2--->正在卖第50张票
            Thread-2--->正在卖第49张票
            Thread-2--->正在卖第48张票
            Thread-2--->正在卖第47张票
            Thread-2--->正在卖第46张票
            Thread-2--->正在卖第45张票
            Thread-2--->正在卖第44张票
            Thread-2--->正在卖第43张票
            Thread-2--->正在卖第42张票
            Thread-2--->正在卖第41张票
            Thread-2--->正在卖第40张票
            Thread-2--->正在卖第39张票
            Thread-2--->正在卖第38张票
            Thread-2--->正在卖第37张票
            Thread-2--->正在卖第36张票
            Thread-2--->正在卖第35张票
            Thread-2--->正在卖第34张票
            Thread-2--->正在卖第33张票
            Thread-2--->正在卖第32张票
            Thread-2--->正在卖第31张票
            Thread-2--->正在卖第30张票
            Thread-2--->正在卖第29张票
            Thread-2--->正在卖第28张票
            Thread-2--->正在卖第27张票
            Thread-2--->正在卖第26张票
            Thread-2--->正在卖第25张票
            Thread-2--->正在卖第24张票
            Thread-2--->正在卖第23张票
            Thread-2--->正在卖第22张票
            Thread-2--->正在卖第21张票
            Thread-2--->正在卖第20张票
            Thread-2--->正在卖第19张票
            Thread-2--->正在卖第18张票
            Thread-2--->正在卖第17张票
            Thread-2--->正在卖第16张票
            Thread-2--->正在卖第15张票
            Thread-2--->正在卖第14张票
            Thread-2--->正在卖第13张票
            Thread-2--->正在卖第12张票
            Thread-2--->正在卖第11张票
            Thread-2--->正在卖第10张票
            Thread-2--->正在卖第9张票
            Thread-2--->正在卖第8张票
            Thread-2--->正在卖第7张票
            Thread-2--->正在卖第6张票
            Thread-2--->正在卖第5张票
            Thread-2--->正在卖第4张票
            Thread-2--->正在卖第3张票
            Thread-2--->正在卖第2张票
            Thread-2--->正在卖第1张票
        */
    }

}

同步技术的原理:

  • 使用了一个锁对象,这个锁对象叫同步锁,也叫对象锁,也叫对象监听器

3个(t0、t1、t2)个线程开始抢夺 cpu 的执行权,谁抢到了谁执行run方法开始卖票。

  • t0 抢到了cpu的执行权,开始执行run方法,遇到 synchronized 代码块,这时 t0 会检查 synchronized 代码块是否存在锁对象,发现 【存在锁对象】 ,就会获取锁对象,进入到同步中执行;
  • t1 抢到了cpu的执行,开始执行 run 方法,遇到 synchronized 代码块,这时 t1 会检查 synchronized 代码块是否存在锁对象,发现【不存在锁对象】,t1 就会进入阻塞状态,会一直等待 t0 线程归还锁对象,一直到 t0 线程执行完同步代码,会把锁对象归还给同步代码块,t1 才会获取锁对象进入到同步中执行。
    总结:同步中的线程,没有执行完毕不会释放锁对象,同步外的线程没有锁对象进不去同步。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值