Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 关于同步关键字?_Java - Fatal编程技术网

Java 关于同步关键字?

Java 关于同步关键字?,java,Java,ReentrantLock不是重点,关键是同步代码块。很有可能连续“AAA级”获得 如果锁刚刚被释放,这似乎会使获得锁变得更容易,那么为什么呢?这是编译器优化吗 如果锁刚刚被释放,这似乎会使获得锁变得更容易,那么为什么呢 这样看:假设每次到达同步块时线程都会改变。这不是很有效(因为更改线程会有成本) 在您的代码中,当前线程并不表示其他线程可以运行,除非在同步块中它仍然持有锁 当您将睡眠移到同步块之外时,可以看到这一点: try{ synchronized (lock) {

ReentrantLock不是重点,关键是同步代码块。很有可能连续“AAA级”获得

如果锁刚刚被释放,这似乎会使获得锁变得更容易,那么为什么呢?这是编译器优化吗

如果锁刚刚被释放,这似乎会使获得锁变得更容易,那么为什么呢

这样看:假设每次到达同步块时线程都会改变。这不是很有效(因为更改线程会有成本)

在您的代码中,当前线程并不表示其他线程可以运行,除非在同步块中它仍然持有锁

当您将睡眠移到同步块之外时,可以看到这一点:

try{
     synchronized (lock) {
         System.out.println(Thread.currentThread().getName()+" get,");
     }
     TimeUnit.SECONDS.sleep(2);
 }catch(InterruptedException e) {
     e.printStackTrace();
 }finally {

 } 
我的情况是:

AAA get, BBB获得, CCC得到, DDD get, CCC得到, AAA get, DDD get, BBB获得, DDD get, AAA get, BBB获得, CCC得到

所以线程每次都会更改,因为当前线程指示它要停止(调用睡眠),并且其他线程可用

最后,JVM将决定交换线程,即使不调用sleep,例如100次迭代:

for(int i = 0 ; i < 100;i++) {
    synchronized (lock) {
        System.out.println(Thread.currentThread().getName()+" get,");
    } 
} 
for(int i=0;i<100;i++){
已同步(锁定){
System.out.println(Thread.currentThread().getName()+“get”);
} 
} 
就我而言,我确实得到了:

AAA get, AAA get, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, CCC得到, AAA get, AAA get, AAA get, AAA get, AAA得到

再说一遍:

CCC得到, CCC得到, CCC得到, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, DDD get, CCC得到, CCC得到, CCC得到, CCC得到, AAA get, AAA get, AAA get, AAA get, AAA get, AAA get, CCC得到, CCC得到, CCC得到, 得到


因此线程会发生变化,但时间和顺序根本无法保证。

在深入研究之前,需要注意以下几点:

  • 未指定Java线程调度程序的行为。这里实际发生的一切都在正确行为的“范围”之内

  • 您的测试代码没有在此处测试
    ReentrantLock
    的行为。实际上,您正在将锁实例用作基本监视器或互斥体。您不能将
    同步
    锁定
    对象一起使用


在运行代码的平台上,最后执行的线程似乎得到了优先权。。。。在一定程度上。我得到了与您的报告类似的行为,但是当线程循环较长时,我确实看到了切换。相比之下,皮罗看到了不同的行为。(我认为这可能是操作系统差异造成的。)

这是怎么回事?实际上的行为部分是由操作系统的本机线程调度程序实现决定的,部分是由实际发生的事情决定的

默认情况下,典型的本机线程调度程序不实现“公平”调度。如果两个本机线程具有相同的优先级,则不能保证每个线程都能获得公平的共享。相反,调度器可以优化以最小化上下文切换开销或调度开销。因此,不同操作系统的不同行为是可以预期的

另一个要考虑的是这个例子中线程的行为。承载监视器的线程执行以下操作:

  • 它从
    睡眠中醒来
  • 它释放监视器
  • 它会解开另一条线
  • 它试图重新获取监视器
  • 被解列的线程也会尝试获取监视器

    所以,问题是,谁将竞相获得显示器?看起来,最初持有监视器的线程通常会赢(至少在我的机器上是这样)

    为什么??很难说:

    • 可能是该线程在调度另一个线程之前从unpark系统调用返回
    • 可能是由于TLAB未命中或内存缓存未命中,未被解析的线程通常会受到阻碍
    • 它可能是其他东西;e、 我没有想到的事情
    但无论如何,这不太可能是一个经过深思熟虑的设计决策,即优先考虑一个线程而不是另一个线程。可能就是这样发生的

    (JVM中监视器的实际实现非常复杂。请查看OpenJDK 11代码库中的
    synchronizer.cpp
    objectMonitor.cpp
    …这只处理JVM端。)


    这是编译器优化吗


    我不这么认为。JIT编译器确实优化了监视器的进入和退出序列,但这仅在监视器未竞争时处理“快速路径”的进入/退出。在本例中,监视器是争用的

    这只是不确定的行为。RenetrantLock不应与synchronized关键字一起使用(以获取对象监视器)。检查。当您替换
    Lock Lock=new ReentrantLock(true)时,您的代码将(mis)以相同的方式运行带有
    对象锁=新对象()也许你误解了我的话,RenetrantLock不是重点,关键是同步代码块,很有可能是连续的“AAA get”,你应该用一个对象替换ReentrantLock并修复这个问题的标题。你把它弄糊涂了。本质上,行为没有定义,您有一个竞争条件。它可能会在不同的平台上改变,但我也是苏
    
    try{
         synchronized (lock) {
             System.out.println(Thread.currentThread().getName()+" get,");
         }
         TimeUnit.SECONDS.sleep(2);
     }catch(InterruptedException e) {
         e.printStackTrace();
     }finally {
    
     } 
    
    for(int i = 0 ; i < 100;i++) {
        synchronized (lock) {
            System.out.println(Thread.currentThread().getName()+" get,");
        } 
    }