当前位置: 首页 > 面试题库 >

Java线程缓存何时刷新?

严瀚昂
2023-03-14
问题内容

线程1:正在执行此循环

while(running) {
// Do Task()
} 
println("Done");

线程2将运行错误设置为假如果运行是易失性变量,则线程1退出循环并显示“完成”。

我的问题是,如果运行不是易失的,那么Thread1何时从主内存中读取运行变量?

注意:我很了解同步和volatile变量之间的关系,但是即使运行不是volatile或同步的,线程1也会停止。所以我的问题是,鉴于没有同步或没有波动,线程1什么时候决定从主存储器读取数据


问题答案:

这在JLS的 Threads and
Locks

部分中进行了描述。

根据同步顺序定义何时需要线程从主存储器读取线程,并且该线程发生在顺序之前。基本上说,为了使 读取 产生最后 写入 的值,需要在读取 之前
进行写入。

事前发生的关系大致上是根据锁定/解锁动作定义的,并且(除了少数例外)归结为使用同步方法和块。除非您要处理volatile变量,否则最重要的是通常需要同步对共享数据的所有访问,最好通过AtomicBoolean,a
BlockingQueue或其他一些java.util.concurrent类。

17.4.4同步顺序

每个执行都有一个同步顺序。同步顺序是执行中所有同步动作的总顺序。对于每个线程t,t中的同步动作(第17.4.2节)的同步顺序与t的程序顺序(第17.4.3节)一致。

同步动作在动作上引发了 同步关系定义如下:

  • 监视器m上的解锁操作与m上的所有后续锁定操作(其中同步根据同步顺序定义)同步。
  • 对易失性变量(第8.3.1.4节)v的写操作与任何线程对v的所有后续读取进行同步(其中,后续操作根据同步顺序定义)。
  • 启动线程的动作与它启动的线程中的第一个动作同步。
    * 将默认值(零,false或null)写入每个变量与每个线程中的第一个动作同步。尽管在分配包含变量的对象之前将默认值写入变量似乎有些奇怪,但是从概念上讲,每个对象都是使用默认初始化值在程序开始时创建的。
  • 线程T1中的最终操作与另一个线程T2中检测到T1已终止的任何操作同步。T2可以通过调用T1.isAlive()或T1.join()来实现。
    * 如果线程T1中断了线程T2,则T1的中断将与任何其他线程(包括T2)确定T2已被中断的任何点同步(通过抛出InterruptedException或调用Thread.interrupted或Thread.isInterrupted)。

与边缘同步的源称为发布,而目标称为获取。

17.4.5订单发生前

可以通过事前发生关系来排序两个动作。如果一个动作发生在另一个动作之前, 则第 一个动作 对第二个 动作 可见,并在第二个
动作之前 排序。

如果我们有两个动作x和y,我们写hb(x,y)表示x发生在y之前。

  • 如果x和y是同一线程的动作,并且x按程序顺序位于y之前,则hb(x,y)。
  • 从对象的构造函数的末尾到该对象的终结器(第12.6节)的开始之间存在一个巧合。
  • 如果动作x 后面的动作y 同步 ,那么我们也有hb(x,y)。
  • 如果hb(x,y)和hb(y,z),则hb(x,z)。

应当指出的是,两个动作之间先发生后发生的关系并不一定意味着它们必须在实现中按该顺序进行。如果重新排序产生的结果与合法执行相符,则不合法。

更新:如果不存在之前发生的关系, 则永远不需要线程“刷新其缓存”
。这个问题及其被接受的答案提供了一个具体的例子。

这是已接受答案的稍作修改的版本:

public class Test {

    static boolean keepRunning = true;

    public static void main(String[] args) throws InterruptedException {

        (new Thread() {
            public void run() {
                while (keepRunning) {
                }
            }
        }).start();

        System.out.println(keepRunning);
        Thread.sleep(1000);
        keepRunning = false;
        System.out.println(keepRunning);

        // main thread ends here, but the while-thread keeps running.
        // (but not if you change the keepRunning to volatile).
    }
}


 类似资料:
  • 问题内容: 这是关于Java线程词汇的一个非常基本的问题。 我看不到任何可能的重复项,但可能存在。 Oracle文档中“ 活着 ”一词指的是什么? 是方法尚未完成时还是其他参数? 问题答案: 根据您提到的Javadoc: 如果线程已经启动但尚未死亡,则该线程是活动的。 线程在调用其方法时“启动”,并在其方法结束时“死亡” ,或在调用时(现在已弃用)。因此,是的,当线程的方法仍在进行中时,该线程为“

  • 我刚刚开始研究Java的类和方法。根据API,生成的线程池重用现有的对象来执行新任务。 我有点困惑这是如何实现的,因为我在API中找不到任何方法可以设置现有对象的行为。 例如,可以从对象创建新的,这使得调用的方法。但是,API中没有将作为参数的setter方法。 我会很感激你的指点。

  • 我需要运行 DAXPY 线性代数核的时序。天真地,我想尝试这样的事情: 如果需要,完整的代码链接位于末尾。 问题是,填充操作数 x 和 y 的内存访问将导致它们被放置在处理器缓存中。因此,在 DAXPY 调用中对内存的后续访问比在生产运行中实际访问要快得多。 我比较了两种解决这个问题的方法。第一种方法是通过clflush指令从所有级别的缓存中刷新操作数。第二种方法是读取一个非常大的数组,直到操作数

  • 我的应用程序的写入吞吐量很低,我可以管理2-3分钟的更改,以反映在solr搜索结果中 目前,我通过索引应用程序进行提交(在每批文档之后),并在solr端配置了以下内容: 选择配置的原因来自我对以下内容的理解: 我的应用程序被大量读取需要大量缓存,我负担不起刷新缓存的费用。因此,我已经完全禁用了软提交。 我已经禁用了opensearch cher,因为如果我不这样做,它会使不可取的顶级缓存无效 在生

  • 问题内容: 我刚刚开始研究Java的类和方法。根据API,生成的线程池将现有对象重用于新任务。 我对此感到有些困惑,因为我无法在API中找到任何方法来设置现有对象的行为。 例如,您可以创建一个 新的 从一个对象,这使得调用的方法。但是,API中没有使用a 作为参数的setter方法。 我将不胜感激任何指针。 问题答案: 执行人员在后台为您完成所有工作。是的,它仅使用现有的线程API。 下面的链接提

  • 问题内容: 我在具有数据库后端和基于EHCache的缓存的Spring多线程Web服务上遇到缓存问题。该服务有许多客户端一次又一次地请求同一个对象,每秒有数十个请求。仅频繁请求几个对象,而不经常请求大量其他对象。对象可以每隔几分钟更改一次,因此将缓存的TTL设置为一分钟。从数据库加载对象很慢,并且至少需要几秒钟。 首先,我使用了一个简单的实现来获取对象: 检查对象是否在缓存中。 如果是,请从缓存中