并发之synchronized关键字的应用

并发之synchronized关键字的应用

synchronized关键字理论基础

前两章我们学习了下java内存模型的相关知识, 现在我们来讲讲逢并发必出现的synchronized关键字。

作用

synchronized是Java中的关键字,是一种同步锁。依赖JVM实现。

JMM对synchronized约束

  1. 线程解锁前,必须将变量的最新值刷新回主内存。

  2. 线程加锁时,将情况工作内存中变量的共享值,从而使变量从主内存中读取最新的值。

注意:加锁和解锁的锁必须是同一把锁。

synchronized关键字应用方向

它修饰的对象有以下几种:
1.修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2.修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3.修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4.修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

并发测试常用类:

线程池创建方式:

ExecutorService 线程池,每一个线程代表一次并发。

ExecutorService executorService =Executors.newCachedThreadPool();

模拟并发次数:

Semaphore 同一时间可以一同运行的线程数量。

Semaphore semaphore = new Semaphore(threadTotal);

模拟并发总量:

CountDownLatch 运行多少个线程后才能再次往下执行、

CountDownLatch countDownLatch = new CountDownLatch(clientTotal);

实际应用

修饰代码块

/**
 * 同步代码块
 */
@Slf4j
public class SyncCodeBlock {
    private static final int COUNT = 5;

    public void syncCodeBlock(String block) {
        synchronized (this){
            for(int i =0;i<COUNT;i++){
                log.info("同步块{}并发-{}",block,i);
            }
        }
        for(int i =0;i<COUNT;i++){
            log.info("异步块{}并发-{}",block,i);
        }

    }
    public void asynCodeBlock(int block) {
        for(int i =0;i<COUNT;i++){
            log.info("代码块{}并发-{}",block,i);
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService =Executors.newCachedThreadPool();
        SyncCodeBlock syncCodeBlock = new SyncCodeBlock();
        executorService.execute(()->{
            syncCodeBlock.syncCodeBlock("A");
        });
        executorService.execute(()->{
            syncCodeBlock.syncCodeBlock("B");
        });
    }
}

结果

同步块A并发0
同步块A并发1
同步块A并发2
同步块A并发3
同步块A并发4
异步块A并发0
异步块A并发1
异步块A并发2
异步块A并发3
同步块B并发0
同步块B并发1
同步块B并发2
同步块B并发3
同步块B并发4
异步块B并发0
异步块B并发1
异步块A并发4
异步块B并发2
异步块B并发3
异步块B并发4

A线程执行同步代码块时并没有B线程干扰,说明A线程锁住了对象。
A线程执行完同步之后释放了锁,B的同步异步代码块和A的异步代码块才开始执行。

由上述例子可以证明
同步代码块作用范围只在synchronized{}括起来的部分。而锁定锁定的是这个对象本身。
**

@Slf4j
public class SyncMethod {
    private static final int COUNT = 5;


    public synchronized void  syncMethod(String block) {
        for(int i =0;i<COUNT;i++){
//            log.info("同步{}并发-{}",block,i);
            System.out.println("同步"+block+"并发"+i);
        }
    }
    public void asynMethod(String block) {
        for(int i =0;i<COUNT;i++){
//            log.info("异步块{}并发-{}",block,i);
            System.out.println("异步"+block+"并发"+i);
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        SyncMethod syncMethod = new SyncMethod();
        executorService.execute(()->{
            syncMethod.syncMethod("A");

        });
        executorService.execute(()->{
            syncMethod.syncMethod("B");
        });
    }
}

作用于方法

同步A并发0
同步A并发1
同步A并发2
同步A并发3
同步A并发4
同步B并发0
同步B并发1
同步B并发2
同步B并发3
同步B并发4

A线程执行同步代码是连续的,并没有B参入。说明锁住了对象
A线程执行完成后B线程执行自己的锁定方法。

上述例子说明作:
同步的作用范围是整个方法而锁定的是整个方法所在对象那个的本身

作用于静态方法、类

public class SyncStaticMethod {
    private static final int COUNT = 10;

    public synchronized static void syncStaticMethod(String block){
        for(int i =0;i<COUNT;i++){
            System.out.println("静态同步"+block+"并发"+i);
        }
    }

    public static void asynStaticMethod(String block){
        for(int i =0;i<COUNT;i++){
            System.out.println("静态异步"+block+"并发"+i);
        }
    }


    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for(int j= 0;j<10;j++){
            int finalJ = j;
            executorService.execute(() -> {
                SyncStaticMethod.syncStaticMethod(""+ finalJ);
            });
        }

    }

}

添加关键字效果

静态同步0并发0
静态同步0并发1
静态同步0并发2
静态同步0并发3
静态同步0并发4
静态同步0并发5
静态同步0并发6
静态同步0并发7
静态同步0并发8
静态同步0并发9
静态同步2并发0
静态同步2并发1
静态同步2并发2
静态同步2并发3
静态同步2并发4
静态同步2并发5
静态同步2并发6
静态同步2并发7
静态同步2并发8
静态同步2并发9
静态同步1并发0
静态同步1并发1
静态同步1并发2
静态同步1并发3
静态同步1并发4
静态同步1并发5
静态同步1并发6
静态同步1并发7
静态同步1并发8
静态同步1并发9
静态同步3并发0
静态同步3并发1
静态同步3并发2
静态同步3并发3
静态同步3并发4
静态同步3并发5
静态同步3并发6
静态同步3并发7
静态同步3并发8
静态同步3并发9
静态同步6并发0
静态同步6并发1
静态同步6并发2
静态同步6并发3
静态同步6并发4
静态同步6并发5
静态同步6并发6
静态同步6并发7
静态同步6并发8
静态同步6并发9
静态同步5并发0
静态同步5并发1
静态同步5并发2
静态同步5并发3
静态同步5并发4
静态同步5并发5
静态同步5并发6
静态同步5并发7
静态同步5并发8
静态同步5并发9
静态同步4并发0
静态同步4并发1
静态同步4并发2
静态同步4并发3
静态同步4并发4
静态同步4并发5
静态同步4并发6
静态同步4并发7
静态同步4并发8
静态同步4并发9
静态同步9并发0
静态同步9并发1
静态同步9并发2
静态同步9并发3
静态同步9并发4
静态同步9并发5
静态同步9并发6
静态同步9并发7
静态同步9并发8
静态同步9并发9
静态同步8并发0
静态同步8并发1
静态同步8并发2
静态同步8并发3
静态同步8并发4
静态同步8并发5
静态同步8并发6
静态同步8并发7
静态同步8并发8
静态同步8并发9
静态同步7并发0
静态同步7并发1
静态同步7并发2
静态同步7并发3
静态同步7并发4
静态同步7并发5
静态同步7并发6
静态同步7并发7
静态同步7并发8
静态同步7并发9
静态同步0并发0
静态同步0并发1
静态同步0并发2
静态同步0并发3
静态同步0并发4
静态同步0并发5
静态同步0并发6
静态同步0并发7
静态同步0并发8
静态同步0并发9
静态同步2并发0
静态同步2并发1
静态同步2并发2
静态同步2并发3
静态同步2并发4
静态同步2并发5
静态同步2并发6
静态同步2并发7
静态同步2并发8
静态同步2并发9
静态同步1并发0
静态同步1并发1
静态同步1并发2
静态同步1并发3
静态同步1并发4
静态同步1并发5
静态同步1并发6
静态同步1并发7
静态同步1并发8
静态同步1并发9
静态同步3并发0
静态同步3并发1
静态同步3并发2
静态同步3并发3
静态同步3并发4
静态同步3并发5
静态同步3并发6
静态同步3并发7
静态同步3并发8
静态同步3并发9
静态同步6并发0
静态同步6并发1
静态同步6并发2
静态同步6并发3
静态同步6并发4
静态同步6并发5
静态同步6并发6
静态同步6并发7
静态同步6并发8
静态同步6并发9
静态同步5并发0
静态同步5并发1
静态同步5并发2
静态同步5并发3
静态同步5并发4
静态同步5并发5
静态同步5并发6
静态同步5并发7
静态同步5并发8
静态同步5并发9
静态同步4并发0
静态同步4并发1
静态同步4并发2
静态同步4并发3
静态同步4并发4
静态同步4并发5
静态同步4并发6
静态同步4并发7
静态同步4并发8
静态同步4并发9
静态同步9并发0
静态同步9并发1
静态同步9并发2
静态同步9并发3
静态同步9并发4
静态同步9并发5
静态同步9并发6
静态同步9并发7
静态同步9并发8
静态同步9并发9
静态同步8并发0
静态同步8并发1
静态同步8并发2
静态同步8并发3
静态同步8并发4
静态同步8并发5
静态同步8并发6
静态同步8并发7
静态同步8并发8
静态同步8并发9
静态同步7并发0
静态同步7并发1
静态同步7并发2
静态同步7并发3
静态同步7并发4
静态同步7并发5
静态同步7并发6
静态同步7并发7
静态同步7并发8
静态同步7并发9

public class SyncStaticMethod {
    private static final int COUNT = 10;

    public synchronized static void syncStaticMethod(String block){
        for(int i =0;i<COUNT;i++){
            System.out.println("静态同步"+block+"并发"+i);
        }
    }

    public static void asynStaticMethod(String block){
        for(int i =0;i<COUNT;i++){
            System.out.println("静态异步"+block+"并发"+i);
        }
    }


    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for(int j= 0;j<10;j++){
            int finalJ = j;
            executorService.execute(() -> {
                SyncStaticMethod.asynStaticMethod(""+ finalJ);
            });
        }

    }

}

不添加关键字静态方法

静态异步0并发0
静态异步0并发1
静态异步0并发2
静态异步0并发3
静态异步0并发4
静态异步0并发5
静态异步0并发6
静态异步0并发7
静态异步0并发8
静态异步0并发9
静态异步1并发0
静态异步1并发1
静态异步1并发2
静态异步1并发3
静态异步1并发4
静态异步1并发5
静态异步1并发6
静态异步1并发7
静态异步1并发8
静态异步1并发9
静态异步2并发0
静态异步3并发0
静态异步3并发1
静态异步2并发1
静态异步2并发2
静态异步3并发2
静态异步3并发3
静态异步2并发3
静态异步2并发4
静态异步2并发5
静态异步2并发6
静态异步3并发4
静态异步3并发5
静态异步3并发6
静态异步3并发7
静态异步3并发8
静态异步3并发9
静态异步2并发7
静态异步2并发8
静态异步2并发9
静态异步4并发0
静态异步4并发1
静态异步4并发2
静态异步4并发3
静态异步4并发4
静态异步4并发5
静态异步4并发6
静态异步4并发7
静态异步5并发0
静态异步6并发0
静态异步6并发1
静态异步6并发2
静态异步6并发3
静态异步6并发4
静态异步6并发5
静态异步6并发6
静态异步4并发8
静态异步4并发9
静态异步6并发7
静态异步6并发8
静态异步5并发1
静态异步5并发2
静态异步5并发3
静态异步5并发4
静态异步5并发5
静态异步5并发6
静态异步5并发7
静态异步6并发9
静态异步5并发8
静态异步5并发9
静态异步7并发0
静态异步7并发1
静态异步7并发2
静态异步7并发3
静态异步7并发4
静态异步7并发5
静态异步7并发6
静态异步8并发0
静态异步8并发1
静态异步8并发2
静态异步8并发3
静态异步8并发4
静态异步8并发5
静态异步9并发0
静态异步9并发1
静态异步9并发2
静态异步7并发7
静态异步7并发8
静态异步7并发9
静态异步9并发3
静态异步8并发6
静态异步8并发7
静态异步8并发8
静态异步8并发9
静态异步9并发4
静态异步9并发5
静态异步9并发6
静态异步9并发7
静态异步9并发8
静态异步9并发9

一个带有成员变量的demo

public class SyncExample {

    static final int clientTotal = 30000;
    static final int threadTotal = 300;
    static int count = 0;

     synchronized void add() {
        count++;
    }

    public static void main(String[] args) throws Exception {
        SyncExample syncExample = new SyncExample();
        ExecutorService executorService = Executors.newCachedThreadPool();
        Semaphore semaphore = new Semaphore(threadTotal);
        CountDownLatch countDownLatch = new CountDownLatch(clientTotal);

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

            executorService.execute(()->{
                try {
                    semaphore.acquire();
                    syncExample.add();
                    semaphore.release();
                } catch (Exception e) {
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println("总计执行:"+count);
    }
}

总结

synchronized 修饰类型 作用范围 锁定对象 实现
作用于代码块 大括号{}括起来的代码 调用代码块的对象 synchronized(this)
作用于方法 整个方法 调用代码块的对象 public synchronized void xxx()
作用于静态方法 静态方法 该类所有对象 public static synchronized void xxx()
作用于类 synchronized后面括号括起来的部分 该类所有对象 synchronized(xxx.class)

注意:继承并不能使子类继承synchronized关键字,synchronized不属于方法声明的一部分。如需同步需要自己再次添加,

posted @ 2018-05-18 14:45  枫飘雪落  阅读(506)  评论(0编辑  收藏  举报