首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >什么是线程上下文中的缓存,以及在Java中何时使用volatile关键字?

什么是线程上下文中的缓存,以及在Java中何时使用volatile关键字?
EN

Stack Overflow用户
提问于 2018-08-12 03:43:30
回答 2查看 406关注 0票数 1

我的理解是Java允许线程访问共享变量。作为规则,为了确保共享变量被一致地更新,线程应该通过获取强制对这些共享变量执行互斥的锁来确保它独占地使用这些变量。如果一个字段被声明为易失性,在这种情况下,Java内存模型确保所有线程看到该变量的一致的值。

在下面的程序中,tickectsAvailable是一个存储在堆上的共享变量,因为thread1和thread2是在同一个对象"obj“上创建的,所以 thread1和thread2都可以访问obj

我正在尝试理解何时使变量成为可变变量。正确的用例应该在这里,在这种情况下,使"tickectsAvailable“不稳定。我对易失性变量的理解正确吗?

我读到一篇文章说:出于性能原因,每个线程可以将变量从主存复制到CPU缓存中。如果您的计算机包含多个CPU,则每个线程可以在不同的CPU上运行。这意味着,每个线程可以将变量复制到不同CPU的CPU缓存中

在这种情况下,如果我没有使"tickectsAvailable“易失性,那么在只有多个CPU的情况下,如果我这里有多个线程在处理同一个对象(”obj“),那么线程可能会从CPU cache中读取一些更改?

是否应该只在您的计算机包含多个CPU时使用易失性变量?但是如果我在同一个obj和一个cpu上有多个线程,它会有什么行为呢?

代码语言:javascript
复制
class TicketBooking implements Runnable{
        int ticketsAvailable=1;

        public void run(){

               System.out.println("Waiting to book ticket for : "+Thread.currentThread().getName());
               synchronized (this) {
                      if(ticketsAvailable>0){
                            System.out.println("Booking ticket for : "+Thread.currentThread().getName());

                            //Let's say system takes some time in booking ticket (here we have taken 1 second time)
                            try{
                                   Thread.sleep(1000); 
                            }catch(Exception e){}

                            ticketsAvailable--;
                            System.out.println("Ticket BOOKED for : "+ Thread.currentThread().getName());
                            System.out.println("currently ticketsAvailable = "+ticketsAvailable);
                      }
                      else{
                            System.out.println("Ticket NOT BOOKED for : "+ 
                                      Thread.currentThread().getName());
                      }

               }//End synchronization block


        }

    }

    /** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
    public class MyClass {
        public static void main(String args[])
        {
               TicketBooking obj=new TicketBooking();

               Thread thread1=new Thread(obj,"Passenger1 Thread");
               Thread thread2=new Thread(obj,"Passenger2 Thread");

               thread1.start();
               thread2.start();

        }

    }

    /*OUTPUT

    Waiting to book ticket for : Passenger2 Thread
    Waiting to book ticket for : Passenger1 Thread
    Booking ticket for : Passenger2 Thread
    Ticket BOOKED for : Passenger2 Thread
    currently ticketsAvailable = 0
    Ticket NOT BOOKED for : Passenger1 Thread

    */
EN

回答 2

Stack Overflow用户

发布于 2018-08-12 03:49:00

易失性变量保证happen before relation。如果只有一个线程在写,而所有其他线程都在读变量,在这种情况下,易失性变量可以确保线程安全。在其他场景中,您必须根据需要使用其他同步机制。

是否应该只在您的计算机包含多个CPU时使用易失性变量?但是如果我在同一个obj和一个cpu上有多个线程,它会有什么行为呢?

操作系统调度程序为每个线程分配CPU。每个内核可以处理一个或多个线程,这取决于硬件能力。易失性变量是语言中的一个抽象概念,它与硬件功能没有任何直接关系。

票数 0
EN

Stack Overflow用户

发布于 2018-08-12 22:21:17

是否应该只在您的计算机包含多个CPU时使用易失性变量?

除非您正在为embedded system编写代码,否则针对特定硬件平台优化您的代码可能是浪费时间。从长远来看,这甚至可能是一个代价高昂的错误。

如果您正在编写Java代码,那么您很可能正在编写服务、web应用程序、移动应用程序或桌面应用程序。如果你正在编写这些东西中的任何一个,那么你的目标应该是通用的Java平台,或者可能是Java平台和一些特定的SDK或框架。帮你自己一个忙,不要担心任何电脑或手机的型号和型号。

如果字段声明为易失性,...Java ..。确保所有线程都看到一致的变量值

任何时候,当你使用“一致”这个词时,你都应该问自己,“与什么一致?”

如果您将单个变量标记为volatile,那么所有线程都将看到该变量的值与其自身一致。也就是说,如果您有一个double d=0.0;,并且线程A设置了d=1.0;,而线程B几乎同时调用system.out.println(d);,那么线程B肯定会打印0.01.0。它永远不会打印任何其他值。

也许更重要的是,如果一个易失性变量被多次更新,那么所有线程将会就更新发生的顺序达成一致。

但是,如果您希望几个变量彼此一致,那么您应该使用synchronized块或java.util.concurrent.locks.ReentrantLock对象来保护这组变量,而不要使用volatile.

每个线程可以将变量从主存复制到CPU缓存中...

Java中没有“缓存”。Java有自己的memory model。CPU缓存是内存模型背后的隐藏原因。如果您正在为某个特定的计算机平台实现JVM,那么希望Java内存模型能够让您自由地利用该平台的缓存系统。

如果您正在为Java平台编写代码,那么您应该首先关注Java内存模型,以及您的程序在面对它时是否能够正确运行。学习缓存系统是一项课外活动,可以帮助您更好地理解为什么Java是这样的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51803157

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档