【并发编程】 --- synchronized的使用姿势

源码地址:https://github.com/nieandsun/concurrent-study.git

1 总览

synchronized的使用姿势总得来说有三种,分别为:

  • 修饰普通方法
  • 修饰静态方法
  • 修饰非静态代码块

前两种姿势比较单一,而最后一种其实可以有很多姿势。但无论哪种姿势,都必须保证各个线程使用同一把锁。

本篇文章将按如何脑图来叙述synchronized的使用姿势。
在这里插入图片描述


2 synchronized修饰静态方法

package com.nrsc.ch1.base.jmm.syn_study;

public class StaticMethodDemo implements Runnable {
    //共享资源
    static int i = 0;

    /**
     * synchronized 修饰静态方法 --- 锁对象为StaticMethodDemo对应的class对象
     */
    public static synchronized void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000; j++) {
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //注意: synchronized 修饰的是静态方法,锁对象为方法所在对象的class对象,
        //该对象在jvm虚拟机里只有一个,
        //因此这里你想new一个StaticMethodDemo对象,或者new两个都可以
        Thread t1 = new Thread(new StaticMethodDemo());
        Thread t2 = new Thread(new StaticMethodDemo());

        t1.start();
        t2.start();

        //保证线程t1,t2执行完
        t1.join();
        t2.join();
        System.out.println(i);
    }
}

3 synchronized修饰静态方法

package com.nrsc.ch1.base.jmm.syn_study;

public class GeneralMethodDemo implements Runnable {

    //共享资源
    static int i = 0;

    /**
     * synchronized 修饰普通方法 --- 锁对象为当前对象,相当于this
     */
    public synchronized void increase() {
        i++;
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000; j++) {
            increase();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        //注意: synchronized 修饰的是普通方法,锁对象为方法所在的对象
        //因此这里只能new 一个GeneralMethodDemo对象
        GeneralMethodDemo generalMethodDemo = new GeneralMethodDemo();
        Thread t1 = new Thread(generalMethodDemo);
        Thread t2 = new Thread(generalMethodDemo);

        t1.start();
        t2.start();

        //保证线程t1,t2执行完
        t1.join();
        t2.join();

        System.out.println(i);
    }
}

注意: 这里一定要看一下我在new对象时写的注释,并与synchronized修饰静态方法的demo做比较。


4 synchronized修饰非静态代码块

这里我列了4种使用姿势,用静态内部类写在一个类里了,相信大家都应该可以看明白。

package com.nrsc.ch1.base.jmm.syn_study;

import lombok.Getter;
import lombok.Setter;
import org.junit.Test;

/***
 * synchronized修饰非静态代码块 ,无法修饰静态代码块
 */
public class CodeBlockDemo {

//////////////////////////////////////利用this当锁/////////////////////////////////
    private static class CodeBlockDemo1 implements Runnable {

        //共享资源
        static int i = 0;

        public void increase() {

            //利用this即当前对象当锁,锁住下面的代码块
            synchronized (this) {
                i++;
            }
        }

        @Override
        public void run() {
            for (int j = 0; j < 10000; j++) {
                increase();
            }
        }
    }

    @Test
    public void CodeBlockDemo1Test() throws InterruptedException {
        //注意: synchronized的锁使用的是this,即代码块所在的对象,因此
        //因此这里只能new 一个CodeBlockDemo1对象
        CodeBlockDemo1 codeBlockDemo1 = new CodeBlockDemo1();
        Thread t1 = new Thread(codeBlockDemo1);
        Thread t2 = new Thread(codeBlockDemo1);

        t1.start();
        t2.start();

        //保证线程t1,t2执行完
        t1.join();
        t2.join();

        System.out.println(codeBlockDemo1.i);
        System.out.println(CodeBlockDemo1.i);

    }
//////////////////////////////////利用this当锁/////////////////////////////////

///////////////////////////////利用某个对象的class当锁//////////////////////////
    /****
     * 利用某个对象的class类型作为锁
     */
    private static class CodeBlockDemo2 implements Runnable {

        //共享资源
        static int i = 0;

        public void increase() {

            //这可使用的锁就丰富了,本类的class对象、
            //甚至像我这样直接Integer对象的class对象都可以作为唯一锁
            synchronized (Integer.class) {
                i++;
            }
        }

        @Override
        public void run() {
            for (int j = 0; j < 10000; j++) {
                increase();
            }
        }
    }

    @Test
    public void CodeBlockDemo2Test() throws InterruptedException {
        //注意: synchronized的锁使用的是某个对象的class对象作为锁,class对象在JVM里都是唯一的
        //因此这里你想new一个CodeBlockDemo2对象,或者new两个都可以
        Thread t1 = new Thread(new CodeBlockDemo2());
        Thread t2 = new Thread(new CodeBlockDemo2());

        t1.start();
        t2.start();

        //保证线程t1,t2执行完
        t1.join();
        t2.join();

        System.out.println(CodeBlockDemo2.i);

    }
///////////////////////////////利用某个对象的class当锁//////////////////////////

//////////////////////////、////利用某个成员对象当锁1////////////////////////////

    /****
     * 利用某个成员对象作为锁 ---- 成员对象在对像里实例化的情况
     */
    private static class CodeBlockDemo3 implements Runnable {

        //某个成员对象
        private Object lock = new Object();

        //共享资源
        static int i = 0;

        public void increase() {
            
            //利用成员对象作为锁
            synchronized (lock) {
                i++;
            }
        }

        @Override
        public void run() {
            for (int j = 0; j < 10000; j++) {
                increase();
            }
        }
    }

    @Test
    public void CodeBlockDemo3Test() throws InterruptedException {
        //注意: synchronized的锁使用的是某个成员对象,
        //因此这里只能new 一个CodeBlockDemo3对象
        CodeBlockDemo3 codeBlockDemo3 = new CodeBlockDemo3();
        Thread t1 = new Thread(codeBlockDemo3);
        Thread t2 = new Thread(codeBlockDemo3);

        t1.start();
        t2.start();

        //保证线程t1,t2执行完
        t1.join();
        t2.join();

        System.out.println(CodeBlockDemo3.i);

    }
/////////////////////////////////////利用某个成员对象当锁1//////////////////////////


/////////////////////////////////////利用某个成员对象的当锁2////////////////////////

    /****
     * 利用某个成员对象作为锁 ---- new对象时传入锁的情况
     */
    @Setter
    @Getter
    private static class CodeBlockDemo4 implements Runnable {

        //某个成员对象
        private Object lock;

        //共享资源
        static int i = 0;

        public void increase() {

            //利用成员对象作为锁
            synchronized (lock) {
                i++;
            }
        }

        @Override
        public void run() {
            for (int j = 0; j < 10000; j++) {
                increase();
            }
        }
    }

    @Test
    public void CodeBlockDemo4Test() throws InterruptedException {
        //注意: synchronized的锁使用的是某个成员对象,
        //因此这里只能new 一个CodeBlockDemo3对象

        Object lock = new Object();

        CodeBlockDemo4 blockDemo4_1 = new CodeBlockDemo4();
        CodeBlockDemo4 blockDemo4_2 = new CodeBlockDemo4();
        blockDemo4_1.setLock(lock);
        blockDemo4_2.setLock(lock);
        Thread t1 = new Thread(blockDemo4_1);
        Thread t2 = new Thread(blockDemo4_2);

        t1.start();
        t2.start();

        //保证线程t1,t2执行完
        t1.join();
        t2.join();

        System.out.println(CodeBlockDemo4.i);

    }
/////////////////////////////////////利用某个成员对象的当锁2//////////////////////////

}
发布了213 篇原创文章 · 获赞 266 · 访问量 48万+

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/104901604