Java并发编程 - 线程安全性之原子性(三)

5d12d6e200011a9719201080.jpg (1920×1080)

  • 子类继承无法继承synchronized,如果需要在子类中对应的地方加上该关键字即可
  • synchronized修饰范围: 
  • 作用于调用对象时,不同对象对synchronized修饰的代码块或者方法的调用,彼此间是不影响的
  • 作用于所有对象时,彼此之间是有影响的,需要等释放后,另一个对象才能操作

案例一

package com.mmall.concurrency.example.sync;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SynchronizedExample1 {

    // 修饰一个代码块
    public void test1(int j) {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                log.info("test1 {} - {}", j, i);
            }
        }
    }

    // 修饰一个方法
    public synchronized void test2(int j) {
        for (int i = 0; i < 10; i++) {
            log.info("test2 {} - {}", j, i);
        }
    }

    public static void main(String[] args) {
        SynchronizedExample1 example1 = new SynchronizedExample1();
        SynchronizedExample1 example2 = new SynchronizedExample1();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            example1.test1(1);
        });
        executorService.execute(() -> {
            example1.test1(2);
        });
    }
}

案例二

package com.mmall.concurrency.example.sync;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SynchronizedExample1 {

    // 修饰一个代码块
    public void test1(int j) {
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                log.info("test1 {} - {}", j, i);
            }
        }
    }

    // 修饰一个方法
    public synchronized void test2(int j) {
        for (int i = 0; i < 10; i++) {
            log.info("test2 {} - {}", j, i);
        }
    }

    public static void main(String[] args) {
        SynchronizedExample1 example1 = new SynchronizedExample1();
        SynchronizedExample1 example2 = new SynchronizedExample1();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            example1.test1(1);
        });
        executorService.execute(() -> {
            example2.test1(2);
        });
    }
}

案例1 & 案例2 分析

  • 这里 test1 和 test2 其实是一样的道理,因为 test1 包裹的是整个方法体代码块,相当于 test2 包裹整个方法。
  • 锁的是对象,而不是方法。什么意思呢?也就是说不同对象之间执行顺序不受影响。

 

案例三

package com.mmall.concurrency.example.sync;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SynchronizedExample2 {

    // 修饰一个类
    public static void test1(int j) {
        synchronized (SynchronizedExample2.class) {
            for (int i = 0; i < 10; i++) {
                log.info("test1 {} - {}", j, i);
            }
        }
    }

    // 修饰一个静态方法
    public static synchronized void test2(int j) {
        for (int i = 0; i < 10; i++) {
            log.info("test2 {} - {}", j, i);
        }
    }

    public static void main(String[] args) {
        SynchronizedExample2 example1 = new SynchronizedExample2();
        SynchronizedExample2 example2 = new SynchronizedExample2();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            example1.test1(1);
        });
        executorService.execute(() -> {
            example2.test1(2);
        });
    }
}

案例四

package com.mmall.concurrency.example.sync;

import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SynchronizedExample2 {

    // 修饰一个类
    public static void test1(int j) {
        synchronized (SynchronizedExample2.class) {
            for (int i = 0; i < 10; i++) {
                log.info("test1 {} - {}", j, i);
            }
        }
    }

    // 修饰一个静态方法
    public static synchronized void test2(int j) {
        for (int i = 0; i < 10; i++) {
            log.info("test2 {} - {}", j, i);
        }
    }

    public static void main(String[] args) {
        SynchronizedExample2 example1 = new SynchronizedExample2();
        SynchronizedExample2 example2 = new SynchronizedExample2();
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.execute(() -> {
            example1.test1(1);
        });
        executorService.execute(() -> {
            example2.test2(2);
        });
    }
}

案例3 & 案例4 分析

  • 锁的是方法,而不是对象。什么意思呢?也就是说不同对象调用同一个被锁的方法之间执行按顺序来,所以为什么说其实是锁所有的对象,这个说法是有歧义的,应该还是说是锁所有调用该方法的对象。
  • 那么问题来了,不同的对象调用不同的静态sychronized方法也是按先后顺序来?!虽然我测试的结果是支持按顺序来的,不过不知读者有何见解?
  • 目前测试出的结论:在案例3和案例4的基础上,不同对象调用不同sync静态方法,把它看成是一个单元的话,单元之间的执行顺序是不一定的,但是好像执行了很多次又一直是一个规律,个人目测应该是线程池里面的影响。当然内部是不会交错的噢~

5c39ba480001e59819201080.jpg (1920×1080)

对比

  • synchronized 适合竞争不激烈时使用,可读性好,竞争激烈时性能下降很快。
  • lock 适合竞争激烈时使用,能维持常态。
  • atomic 竞争激烈时也能维持常态,性能比lock好,但是只能同步一个值。
发布了1005 篇原创文章 · 获赞 1889 · 访问量 89万+

猜你喜欢

转载自blog.csdn.net/Dream_Weave/article/details/105496901