跳至主要內容

JAVA何时加锁

Sunhb...大约 2 分钟JAVA学习JAVA锁JAVA异常

JVM内存结构

线程代码何时适合加锁?

提示

1. 线程锁如何锁住变量

1.1 问题展示

@Slf4j
public class Interesting {
    volatile int a = 1;
    volatile int b = 1;
    public synchronized void add() {
        log.info("add start");
        for (int i = 0; i < 10000; i++) {
            a++;
            b++;
        }
        log.info("add done");
    }
    public void compare() {
        log.info("compare start");
        for (int i = 0; i < 10000; i++) {
            //a始终等于b吗?
            if (a < b) {
                log.info("a:{},b:{},{}", a, b, a > b);
                //最后的a>b应该始终是false吗?
            }
        }
        log.info("compare done");
    }
}
@GetMapping("wrong2")
public String wrong2() {
    Interesting interesting = new Interesting();
    new Thread(() -> interesting.add()).start();
    new Thread(() -> interesting.compare()).start();
    return "OK";
}


按道理,a 和 b 同样进行累加操作,应该始终相等,compare 中的第一次判断应该始终不会成立,不会输出任何日志。但是,执行代码后发现不但输出了日志,部分ab是不相等的

[15:44:10.805] [Thread-28] [INFO ] [j.c.lock.lockscope.Interesting:25  ] - a:979751,b:979754,false
[15:44:10.805] [Thread-28] [INFO ] [j.c.lock.lockscope.Interesting:25  ] - a:988792,b:988793,true
[15:44:10.805] [Thread-28] [INFO ] [j.c.lock.lockscope.Interesting:25  ] - a:992597,b:992596,true
[15:44:10.805] [Thread-28] [INFO ] [j.c.lock.lockscope.Interesting:25  ] - a:996236,b:996237,true
[15:44:10.805] [Thread-28] [INFO ] [j.c.lock.lockscope.Interesting:25  ] - a:999856,b:999857,false
[15:44:10.805] [Thread-27] [INFO ] [j.c.lock.lockscope.Interesting:18  ] - add done
[15:44:10.806] [Thread-28] [INFO ] [j.c.lock.lockscope.Interesting:29  ] - compare done

1.2 问题分析

原因分析,目前尽管add函数使用synchronized关键字解决了add函数线程安全性,但是compare函数比较过程中,比较ab两个变量,需要先加载a,b两个变量再比较,如果在加载过程中运行了add函数,导致b多进行了一次b++操作,b变量则大于a变量,如果a多进行一次a++操作,a变量则大于b变量。

1.3 问题解决

应该在addcompare两个函数上都增加排他锁,保证在增加和比较过程中线程的安全性。

public synchronized void compare() {
      log.info("compare start");
      for (int i = 0; i < 10000; i++) {
          //a始终等于b吗?
          if (a < b) {
              log.info("a:{},b:{},{}", a, b, a > b);
              //最后的a>b应该始终是false吗?
          }
      }
      log.info("compare done");
  }
@GetMapping("right2")
public String right2() {
    Interesting interesting = new Interesting();
    new Thread(() -> interesting.add()).start();
    new Thread(() -> interesting.compareRight()).start();
    return "OK";
}

此时运行不会出现ab变量不同情况

[16:08:07.512] [Thread-29] [INFO ] [j.c.lock.lockscope.Interesting:13  ] - add start
[16:08:07.522] [Thread-29] [INFO ] [j.c.lock.lockscope.Interesting:18  ] - add done
[16:08:07.522] [Thread-30] [INFO ] [j.c.lock.lockscope.Interesting:33  ] - compare start
[16:08:07.524] [Thread-30] [INFO ] [j.c.lock.lockscope.Interesting:40  ] - compare done
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.0.0-alpha.1