java 并发编程 - synchronized(2)

128 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

修饰对象

1.修饰静态方法,锁定的是该类

 public synchronized static void test() {
 // xxxx
 }

2.修饰普通方法,锁定的是对象

 public synchroized void eat() {
    // xxx
 }

3.同步代码块指定对象或者类

 public void test() {
   synchronized(Object.class) {
     // xxxx
  }
 }

多个sync方法之间的联系

  • 2个被修饰的静态方法

    • eat和sleep属于同一个锁(类),会有先后顺序执行
     public synchronized void eat() throws InterruptedException {
             System.out.println(Thread.currentThread().getName()+",eat");
             TimeUnit.SECONDS.sleep(1);
        }
     ​
         public synchronized void sleep() throws InterruptedException {
             System.out.println(Thread.currentThread().getName()+",sleep");
             TimeUnit.SECONDS.sleep(1);
        }
    
  • 2个被修饰的普通方法和一个不被修饰的方法

    • 如果这两个被修饰方法的对象为同一个锁成立,有先后顺序
    • 普通方法不受影响,第一时间就会执行
 public synchronized void eat() throws InterruptedException {
         System.out.println(Thread.currentThread().getName()+",eat");
         TimeUnit.SECONDS.sleep(1);
    }
 ​
     public synchronized void sleep() throws InterruptedException {
         System.out.println(Thread.currentThread().getName()+",sleep");
         TimeUnit.SECONDS.sleep(1);
    }
 ​
     public void play() throws InterruptedException {
         System.out.println(Thread.currentThread().getName()+"play");
         TimeUnit.SECONDS.sleep(1);
    }

和volatile比较

两者都能实现锁的功能

Volatile

对要操作的变量修饰。那么由于可见性,在set后其他线程能够看见最新的数据

 private volatile int age;
 ​
     public int getAge() {
         return age;
    }
 ​
     public void setAge(int age) {
         this.age = age;
    }

synchronized

锁如何实现可见性

 private int age;
 ​
     public synchronized int getAge() {
         return age;
    }
 ​
     public synchronized void setAge(int age) {
         this.age = age;
    }

适用情况

读多写少的情况下,volatile的修改刷新回主存的次数少,,大部分情况都是从CPU的缓存中读取,性能损耗少,速度快

读少写多的情况下,volatile修改刷回主存的次数变多,CPU嗅探次数频繁,每次修改完都要重新从主存中获取缓存,性能损耗大,速度慢

synchronized虽然需要上下文切换(内核态和用户态的切换),但是如果写入的速度快,那么阻塞的时间就少,速度就快。重量级锁(synchronized)是提高吞吐量的唯一选择