线程安全问题

当多个线程访问同一个共享资源可能会出现线程安全问题

需求:我们开模拟售票窗口,实现多个售票同时卖“速度与激情8”(多个窗口一起卖100张票)

分析:多个窗口相当于多个线程,每个线程做的事情都是一样的,卖100张票(任务放到Runnable中)

public class DiyThread {

    static int tick = 100;
    public static void main(String[] args) {

        Runnable runnable = ()->{
            while (true){
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (tick > 0){
                    tick--;
                    System.out.println(Thread.currentThread().getName()+"剩余"+tick);
                }else {
                    break;
                }
            }
        };
        Thread t1 = new Thread(runnable);
        Thread t2 = new Thread(runnable);
        Thread t3 = new Thread(runnable);
        t1.start();
        t2.start();
        t3.start();
    }
}

 线程问题到底是如何产生的呢

原子性
定义:即一个或者多个操作作为一个整体,要么全部执行,要么都不执行,并且操作在执行过程中不会被线程调度机制打断;而且这种操作一旦开始,就一直运行到结束,中间不会有任何上下文切换。

例如转账问题,A向B转1000元,该过程分解成两个步骤:

1、A账户减掉1000元;

2、B账户增加1000元。

上述两个步骤如果中途被打断会造成什么后果?A账户已经被扣掉1000了,但是B账户确没有收到1000,这种情况肯定要禁止的。所以这2个操作必须要具备原子性才能保证不出现一些意外的问题。

在代码编程中经常使用如下语句:

i = 0;       //1
j = i ;      //2
i++;         //3
i = j + 1;   //4
分析上述四种语句,哪些是原子操作,哪些不是。

1在Java中,对基本数据类型的变量和赋值操作都是原子性操作;

2中包含了两个操作:读取i,将i值赋值给j

3中包含了三个操作:读取i值、i + 1 、将+1结果赋值给i;

4中同三一样

从上面分析中,其实可以初步总结出,语句中包含多个操作的情况,通常都不具备原子性,那么在实际开发过程中如果只是单线程的话是没问题的,但是多线程就很有可能得到意想不到的结果了。主要原因就是在操作过程中其它线程中途可能会写入数据,导致读取到的可能是脏数据。

要想在多线程环境下保证原子性,则可以通过锁、synchronized来确保。volatile是无法保证复合操作的原子性。
 

Java内存模型(Java Memory Model,JMM)

今天简单聊聊什么叫做 Java 内存模型,不是 JVM 内存结构哦。

JMM 是一个语言级别的内存模型,处理器的硬件模型是硬件级别,Java中的内存模型是内存可见性的基本保证。从而为我们 volatile 实现内存可见性提供了基石。主要目的就是让 Java 程序员在各种平台下达到一致性访问效果

JMM决定一个线程对共享变量的写入何时对另一个线程可见,尤其是在对共享变量的读写,修改后其他线程立刻内读取到,这个就是JMM主要作用。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。Java内存模型的抽象示意如图所示。

内存模型是一个抽象的概念 他描述了多线程操作共享变量的时候 这个共享变量必须存放在主内存当中,线程不能直接更改主内存中的共享变量,要想更改共享变量,他必须把共享变量加载到他自己的工作内存当中,在工作内存当中有一个共享变量的副本,只能在这个里修改变量,改完之后在从新写进主内存当中,这时候主内存的变量就会改变,这时候问题就产生了,线程A去修改变量线程B也会读取到主内存的变量这个是两个线程获取的变量都是相同的,这就是javaJMM模型造成的原子性问题        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值