解决线程安全问题_同步代码块

同步代码块

synchronized关键字可以用于方法中的某个区块中,表示只对这个区块这个区块的资源实现互斥访问

卖票案例出现了线程安全问题
卖出了不存在的票和重复的票

解决线程安全问题的一种方案:使用同步代码块
格式
synchronized(同步锁){
需要同步操作的代码
}

注意:

1.通过代码块中的锁对象,可以使用任意的对象
2.但是必须保证多个线程使用的锁对象是同一个
3.锁对象作用:把同步代码块锁住,只让一个线程在同步代码块中执行

package com.Thread.Synchronized;

import java.util.Objects;

public class RunnableImpl implements Runnable {
    //定义一个多个线程共享的资源
    private  int ticket = 100;

    //创建一个锁对象
    Object obj = new Object();

    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复进行
        while (true){
          //同步代码块
            synchronized (obj){
                //提高安全问题出现的概率,让程序睡眠
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //先判断票是否存在
                if (ticket>0){
                    //票存在,卖票 ticket--
                    System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket+"张票");
                    ticket--;
                }
            }
        }
    }
}

测试类

package com.Thread.Synchronized;

/*
   模拟卖票案例
   创建3个线程,同时开启,对共享的票进行出售
 */
public class Demo01Ticket {
    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        RunnableImpl run = new RunnableImpl();
        //创建Thread类对象。构造方法中传递Runnable接口的实现对象
        Thread t0 = new Thread(run);
        Thread t1 = new Thread(run);
        Thread t2 = new Thread(run);
        //调用start方法开启多线程
        t0.start();
        t1.start();
        t2.start();
    }
}
同步技术的原理
  • 使用了一个锁对象,这个锁对象叫同步锁,也叫对象锁,也叫对象监视器
  • 3个线程一起抢夺cpu的执行权,谁抢到了谁执行run方法进行卖票
  • t0抢到了cpu的执行权,执行run方法,遇到synchronized代码块
    这时t0会检查synchronized代码块是否有锁对象
    发现有,就会获取到锁对象,进入到同步中执行
  • t1抢到了cpu的执行权,执行run方法,遇到synchronized代码块
    这时t1会检查synchronized代码块是否有锁对象
    发现没有,t1就进入到阻塞状态,会一直等待t0线程归还锁对象
    一直到t0线程执行完同步中的代码,会把锁对象归还给同步代码块
    t1才能获取到锁对象进入到同步中执行
总结:
  • 同步中的线程,没有执行完毕不会释放锁,同步外的线程没有锁进不去
  • 同步保证了只能有一个 线程在同步中执行共享数据,保证了安全
  • 程序频繁的判断锁,获取锁,释放锁,程序的效率会降低

你可能感兴趣的:(多线程,java)