实现Runnable解决多线程数据安全问题

news/2024/5/17 18:15:34 标签: Runnable, 多线程, 线程安全, synchronized,

xl_echo编辑整理,欢迎转载,转载请声明文章来源。更多IT、编程案例、资料请联系QQ:1280023003,加群298140694。百战不败,依不自称常胜,百败不颓,依能奋力前行。——这才是真正的堪称强大!!


之前的文章我们讲到了,四个电影院窗口同时出售50张彩票的问题。在实现的过程中,我们使用Tread继承,达到了需求的效果,但是也提出了一部分问题。这里我们先使用Runnable进行改造之前的程序,实现效果,然后在来阐述之前的问题。

实现Tread完成需求代码如下:

package com.example.mybatisplusdemo.test;

/**
 * @Author xl_echo
 * @Date 2018/8/7 下午1:54
 **/
public class Window extends Thread {

  //售票窗口
  private final String name;

  //有50张电影票
  private static final int MAXTicket = 10000;

  public Window(String name) {
    this.name = name;
  }

  private static int index = 1;

  @Override
  public void run(){
    while (index <= MAXTicket){
      System.out.println("窗口" + name + "当前是第" + (index++) + "张票");
    }
  }

  public static void main(String[] args) {
    Window window1= new Window("1号窗口");
    window1.start();
    Window window2= new Window("2号窗口");
    window2.start();
    Window window3= new Window("3号窗口");
    window3.start();
    Window window4= new Window("4号窗口");
    window4.start();
  }

}

使用Runnable改造,改造后代码如下

package com.example.mybatisplusdemo.test;

/**
 * @Author xl_echo
 * @Date 2018/8/8 上午10:53
 **/
public class Test implements Runnable {

  private int index = 1;

  private final static int MAX = 50;

  @Override
  public void run() {

    while (index <= MAX){
      System.out.println("窗口" + Thread.currentThread() + "当前是第" + (index++) + "张票");
      try{
        Thread.sleep(100);
      }catch (InterruptedException e){
        e.printStackTrace();
      }
    }
  }

  public static void main(String[] args){
    final Test test = new Test();

    Thread windows1 = new Thread(test, "一号窗口");
    Thread windows2 = new Thread(test, "二号窗口");
    Thread windows3 = new Thread(test, "三号窗口");
    Thread windows4 = new Thread(test, "四号窗口");

    windows1.start();
    windows2.start();
    windows3.start();
    windows4.start();

  }

}

输出结果这里就不展示了,因为这里的结果和之前程序的结果是一样的,如果index增大的时候一样会出现线程安全问题。

可能有朋友会发现我们没有使用static修饰index,会不会是没有修饰造成的安全问题,其实不然。比如,有一个线程拿到了index,这个时候准备执行方法,刚好另外一个线程也拿到了index,同时也准备执行方法,这个时候就会造成两个窗口卖了同一张票。2而我们的输出就出现了一下图片中的输出相同票数的情况。当我们的某一个线程拿到了最后一张票的时候,index=50了,刚好该线程进入了休眠。然后其他两个线程进入,也获取到了index发现并大于max,这个时候就会执行卖票,当这边后进入的程序执行完成,前面的程序再次唤醒执行,就会出现卖了51张票。

解决办法:使用synchronized关键字。

  • 但是这个关键字加在什么地方呢?

比如:加在run()方法上面,你会发现基本都是一号窗口买完了所有的票。因为同步在第一条线程进入后,就死了该方法的执行,必须要第一条线程执行完成该方法才能够进入第二线程,所以等第二条进入的时候就会发现index已经大于50了,自然输出结果就是一条线程执行完了所有出票。

public synchronized void run() {...}

这里写图片描述

比如:加在while循环里面,使用synchronized(this){...}括上方法里面的所有代码,这个时候你会发现,基本每次都多出了三张票。因为:while判断的下一步有四条线程执行,到最后一张票的时候,所有线程都拿到了,并且由于的关系,每条线程都执行一次,所以这个时候就多卖了三张。

while (index <= MAX) {
  synchronized (this) {
    ...
  }
}

这里写图片描述

以上程序最终的解决办法:
将同步加在休眠上面,我们会发现我们效果达到了,线程安全问题解决了

synchronized (this) {
  Thread.sleep(100);
}

这里写图片描述

这是什么原因呢?
因为我们加在Thread.sleep(100); 上面的时候,我们的四个线程只有有一个进入休眠,其他的就会进入等待,刚好这时候进入休眠等待的线程就拦截了后的线程进行下一步操作。所以当我们的线程进入休眠的时候,前面的index叠加就已经完成了。

当我们的index叠加到46的时候,执行输出和index再次叠加,刚好每条线程叠加一次,线程进入休眠,后面的想再次叠加也会被拦截。当最前面的线程唤醒之后,后面的线程都已经执行完成了,index自然是要比MAX大。

当然这里也提出一个疑问?大家可以一起思考
那就是index叠加到46的时候,再次循环,第一条线程将index叠加为47,进入休眠,后面的线程在休眠时间内还没有完成最后的三张票出售。这个时候就会不会出现数据安全问题?欢迎大家跟我联系。


http://www.niftyadmin.cn/n/1639241.html

相关文章

深入了解Thread之构造器

xl_echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。更多IT、编程案例、资料请联系QQ&#xff1a;1280023003&#xff0c;加群298140694。百战不败&#xff0c;依不自称常胜&#xff0c;百败不颓&#xff0c;依能奋力前行。——这才是真正的堪称强大&#xf…

认识第一个gradle管理的项目

xl_echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。更多IT、编程案例、资料请联系QQ&#xff1a;1280023003 百战不败&#xff0c;依不自称常胜&#xff0c;百败不颓&#xff0c;依能奋力前行。——这才是真正的堪称强大&#xff01;&#xff01; 通过一键…

RocketMQ四种模式安装(单Master模式,多Master模式,多Master多Slave模式-异步复制,多Master多Slave模式-同步双写)

文章目录 1 RocketMQ安装1.1 单Master模式安装1.2 多Master模式安装1.3 多Master多Slave模式-异步复制1.4 多Master多Slave模式-同步双写1 RocketMQ安装 ​ 官网地址:https://rocketmq.apache.org/ ​ 下载地址:https://rocketmq.apache.org/download ​ 本次下载的版本地…

守护线程简介

xl_echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。更多IT、编程案例、资料请联系QQ&#xff1a;1280023003&#xff0c;加群298140694。百战不败&#xff0c;依不自称常胜&#xff0c;百败不颓&#xff0c;依能奋力前行。——这才是真正的堪称强大&#xf…

rg.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout

错误信息如下&#xff1a; Exception in thread "main" org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeoutat org.apache.rocketmq.client.impl.producer.DefaultMQProducerImpl.sendDefaultImpl(DefaultMQPr…

Idea创建第一个gradle管理的项目

xl_echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。更多IT、编程案例、资料请联系QQ&#xff1a;1280023003&#xff0c;加群298140694。百战不败&#xff0c;依不自称常胜&#xff0c;百败不颓&#xff0c;依能奋力前行。——这才是真正的堪称强大&#xf…

线程方法join

xl_echo编辑整理&#xff0c;欢迎转载&#xff0c;转载请声明文章来源。更多IT、编程案例、资料请联系QQ&#xff1a;1280023003&#xff0c;加群298140694。百战不败&#xff0c;依不自称常胜&#xff0c;百败不颓&#xff0c;依能奋力前行。——这才是真正的堪称强大&#xf…

java中TimeUnit vs Thread.sleep的用法对比

xl_echo编辑整理&#xff0c;交流学习请加1280023003 百战不败&#xff0c;依不自称常胜&#xff0c;百败不颓&#xff0c;依能奋力前行。——这才是真正的堪称强大&#xff01;&#xff01; 本文转载自&#xff1a;https://blog.csdn.net/u012843873/article/details/786243…