编程语言
首页 > 编程语言> > JAVA 线程同步机制

JAVA 线程同步机制

作者:互联网

线程安全问题:

多个线程共享一批数据时,则会出现线程安全问题,看个demo

三个线程 同时卖100张票,此时运行则会出现线程安全问题,运行结果可能会出现卖重复的张数,或者卖不出现的张数。

public class Runnable2 implements Runnable {

    private int ticket = 100;//票数
    @Override
    public void run() {

        while (true){

           if(ticket > 0 ){
               System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
               ticket--;
               try {
                   Thread.sleep(10);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        }
    }

    public static void main(String[] args) {
        Runnable2 r2 = new Runnable2();
        Thread t1 = new Thread(r2);
        Thread t2 = new Thread(r2);
        Thread t3 = new Thread(r2);
        t1.start();
        t2.start();
        t3.start();
    }
}

线程安全问题产生的原理:

重复现象是因为 当多个线程同时执行了System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票"); 此时还没有进行 ticket--,所以会出现重复现象。

出现不该出现的张数是因为 多个线程同时进入if语句 当ticket--为0时,此时ticket为-1,if条件不符合,但此时还有线程在if语句里面,当此线程再执行时就是打印出ticket为-1。


解决线程安全问题:

① 使用同步代码块  先创建一个锁对象  在编写一同步代码块 synchronized(锁对象){可能会出现线程安全的代码}   同步中的线程没有执行完毕不会释放锁,同步外的线程没有锁进不去同步       此方法的缺点就是会降低效率

public class Runnable2 implements Runnable {

    private int ticket = 100;//票数

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

    @Override
    public void run() {

        while (true) {
//创建一个同步代码块
            synchronized (obj) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
                    ticket--;
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

②使用同步方法       

同步方法同样也会把代码锁住 ,让一个线程执行 同步方法的锁对象就是默认的实现类对象(this)

  @Override
    public void run() {

        while (true) {
        //调用方法
         payTicket();
        }
    }
  //创建一个同步方法
    public synchronized void payTicket(){
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
            ticket--;
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

补充:使用静态方法  此时的锁对象不能再是 this 而是本类的class属性

③使用LOCK锁   使用LOCK 要比 synchronize更为灵活  首先创建一个ReentrantLock锁对象 再在代码前加上lock()方法加上锁

最后使用unlock()方法来释放锁。

public class Runnable3 implements Runnable {

    private int ticket = 100;//票数

    //创建一个ReentrantLock锁对象
    Lock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true) {
            
             //开启锁
            lock.lock();
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票");
                ticket--;
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    //释放锁
                    lock.unlock();
                }
            }
           
        }
    }

 

标签:同步,JAVA,Thread,张票,线程,ticket,public
来源: https://blog.csdn.net/qq_42183409/article/details/94658399