java高并发4.2 原子性-锁

 

我们再回顾一下原子性:

原子性提供了互斥访问 ,同一时刻只有一个线程能对他进行操作 . 

同一时刻只有一个线程能对其进行操作的 除了Atomic包之外还有

锁分为两种:

java高并发4.2 原子性-锁

____________________________________________________________________________

synchronized

依赖于JVM去实现锁,因此在这个关键字作用对象的作用范围内,都是同一时刻只能有一个线程对其进行操作的。

synchronized是java中的一个关键字,是一种同步锁。它可以修饰的对象主要有四种:

  • 修饰代码块:大括号括起来的代码,作用于调用的对象

  • 修饰方法:整个方法,作用于调用的对象

  • 修饰静态方法:整个静态方法,作用于所有对象

  • 修饰类:括号括起来的部分,作用于所有对象

____________________________________________________________________________

synchronized 修饰一个代码块

被修饰的代码称为同步语句块,作用的范围是大括号括起来的部分。作用的对象是调用这段代码的对象。

这里用到了 线程池 , 为什么要用线程池呢?

如果不使用线程池,这里一个类对象(example1) 两次调用同一个方法 , 本身就是同步执行的. 因此没法验证具体的影响.

而我们加上线程池之后相当于分别启动了两个线程去执行. (一个没等另一个完就执行了)

 

java高并发4.2 原子性-锁

public class SynchronizedExample {

    public void test(int j){

        synchronized (this){

            for (int i = 0; i < 10; i++) {

                log.info("test - {} - {}",j,i);

            }

        }

    }

    //使用线程池方法进行测试:

    public static void main(String[] args) {

        SynchronizedExample example1 = new SynchronizedExample();

        SynchronizedExample example2 = new SynchronizedExample();

        ExecutorService executorService = Executors.newCachedThreadPool();

        executorService.execute(()-> example1.test(1));

        executorService.execute(()-> example2.test(2));

    }

}

 

结果:不同对象之间的操作互不影响

java高并发4.2 原子性-锁

tip: 当一个方法里都是同步的代码块时, 他的作用和直接修饰方法是一样的

____________________________________________________________________________

synchronized 修饰一个方法

被修饰的方法称为同步方法,作用的范围是大括号括起来的部分,作用的对象是调用这段代码的对象。

public class SynchronizedExample

    public synchronized void test(int j){

        for (int i = 0; i < 10; i++) {

            log.info("test - {} - {}",j,i);

        }

    }

    //验证方法与上面相同

    ...

}

java高并发4.2 原子性-锁

tip2:如果当前类是一个父类,子类调用父类的被synchronized修饰的方法,不会携带synchronized属性,因为synchronized不属于方法声明的一部分

____________________________________________________________________________

synchronized 修饰一个静态方法

作用的范围是synchronized 大括号括起来的部分,作用的对象是这个类的所有对象。

验证:

public class SynchronizedExample{

    public static synchronized void test(int j){

        for (int i = 0; i < 10; i++) {

            log.info("test - {} - {}",j,i);

        }

    }

    //验证方法与上面相同

    ...

}

结果:同一时间只有一个线程可以执行

java高并发4.2 原子性-锁

synchronized 修饰一个类

public class SynchronizedExample{

    public static void test(int j){

        synchronized (SynchronizedExample.class){

            for (int i = 0; i < 10; i++) {

                log.info("test - {}-{}",j,i);

            }

        }

    }

    //验证方法与上面相同

    ...

}

结果:同一时间只有一个线程可以执行

java高并发4.2 原子性-锁

 

原子性操作各方法间的对比

  • synchronized:不可中断锁,适合竞争不激烈,可读性好

  • Lock:可中断锁,多样化同步,竞争激烈时能维持常态

  • Atomic:竞争激烈时能维持常态,比Lock性能好,每次只能同步一个值