先来一部分百度百科上官方说法:

synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块。

引述完毕,上面写的不够直观,直接代码伺候。

首先,我要先分几种情况

synchronized 加在什么地方

1.加在方法上

a.加在非静态方法上

import java.util.concurrent.*;

/**
 * 方法添加同步
 * @author: Leon
 * @date: 2019/4/13 19:28
 */
public class SynchronizedLearn {
    /**
     * 同步方法
     */
    public synchronized void hello() {
        System.out.println(Thread.currentThread().getName() + ":" + "start");
        System.out.println(Thread.currentThread().getName() + ":" + "Hello");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":" + "end");
    }
}

执行代码:

public static void main(String[] args) {
        final SynchronizedLearn synchronizedLearn = new SynchronizedLearn();
        ThreadFactory myThreadFactory = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r);
            }
        };
        //线程池
        ExecutorService singleThreadPool = new ThreadPoolExecutor(
                10, 16, 0L, TimeUnit.MICROSECONDS, new LinkedBlockingDeque<>(1024),
                myThreadFactory, new ThreadPoolExecutor.AbortPolicy()
        );

        //同步方法 单个对象
        /*
        同一对象调用同步方法,
        执行结果:多线程 一个一个执行
         */
//        for (int i = 0; i < 10; i++) {
//            singleThreadPool.execute(() -> {
//                synchronizedLearn.hello();
//            });
//        }

        //同步方法 - 多对象
        /*
        执行结果:多线程 并发执行
        可以理解:方法内部为同步代码块,同步锁加在this上
         */
        for (int i = 0; i < 10; i++) {
            singleThreadPool.execute(() -> {
                new SynchronizedLearn().hello();
            });
        }
}

b.加在静态方法上

/**
     * 同步方法
     */
    public synchronized static void staticHello() {
        System.out.println(Thread.currentThread().getName() + ":" + "start");
        System.out.println(Thread.currentThread().getName() + ":" + "Hello");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":" + "end");
    }

执行代码:

// 同步静态方法
        /*
        执行结果:多线程 一个一个执行
        理解:方法内部为同步代码块,同步锁加在SynchronizedLearn.class上
         */
        for (int i = 0; i < 10; i++) {
            singleThreadPool.execute(() -> {
                SynchronizedLearn.staticHello();
            });
        }

2.加在方法内部

a.对象锁,即synchronized括号内是对象,如this等

//16L  public Long index = 100L;
//17L public Long index = new Long(100);
    /**
     * 同步代码块 锁对象
     */
    public void minusLockIndex() {
        System.out.println(Thread.currentThread().getName() + ":" + "执行等待。。。");
        synchronized (index) {
            System.out.println(Thread.currentThread().getName() + ":" + "start");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + "index=" + index--);
            System.out.println(Thread.currentThread().getName() + ":" + "end");
        }
    }

执行代码:

//同步代码块 一个对象 或者 多个对象
        /*
        执行结果:多线程 一个一个执行
        理解:同步锁加在 index上,线程运行代码块时,发现index已被锁,有其他线程执行,就需要等待当前线程运行完代码块内的程序。
         */
        for (int i = 0; i < 10; i++) {
            singleThreadPool.execute(() -> {
//                synchronizedLearn.minusLockIndex();
                /*
                 * 补充知识点:16L 和 17L 两种定义是不一样的
                 *          16L 会创建一个池,自动装箱会直接从池里取该对象
                 *          17L 会创建新对象
                 * 这里的差异也会导致下面方法执行不一样
                 * 按16L执行的话,就会一个一个执行
                 * 按17L执行的话,就会异步执行
                 */
                new SynchronizedLearn().minusLockIndex();
            });
        }

b.类锁,即synchronized括号内是类,如Object.class等

/**
     * 同步代码块 对象锁
     */
    public void minusLockObject() {
        System.out.println(Thread.currentThread().getName() + ":" + "执行等待。。。");
        synchronized (this) {
            System.out.println(Thread.currentThread().getName() + ":" + "start");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + "index=" + (index--));
            System.out.println(Thread.currentThread().getName() + ":" + "end");
        }
    }

    /**
     * 同步代码块 类锁
     */
    public void minusLockClass() {
        System.out.println(Thread.currentThread().getName() + ":" + "执行等待。。。");
        synchronized (SynchronizedLearn.class) {
            System.out.println(Thread.currentThread().getName() + ":" + "start");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":" + "index=" + (index--));
            System.out.println(Thread.currentThread().getName() + ":" + "end");
        }
    }

执行代码

// 同步代码块 类
        for (int i = 0; i < 10; i++) {
            singleThreadPool.execute(() -> {
                // 代码块内代码 同步执行
//                synchronizedLearn.minusLockObject();//一个对象
                // 代码块内代码 异步执行
//                new SynchronizedLearn().minusLockObject(); //多个对象 对象锁 锁的this
                // 代码块内代码 同步执行
//                new SynchronizedLearn().minusLockClass(); //对个对象,锁类 全局锁 同synchronized static
            });
        }


综上代码执行

总结:同步关键字加在方法上时,如果是非静态方法,则锁定的对象为this;如果是静态方法,则锁定的是类。

同步关键字加在代码块上时,如果后面括号内跟的是对象,及锁定为对象,运行时;如果跟的类,则锁定的是类。





扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄