Java Keyword Synchronized 学习记录

你离开我真会死。 提交于 2020-03-28 06:44:39

Synchronized

Java编程思想:每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分,调用任何synchronized方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized 方法,除非第一个方法完成了自己的工作,并解除锁定。
特点:Jvm层面,非公平,悲观,独占,可重入,重量级。
作用:修饰方法和代码块。

修饰方法和代码块

synchronized修饰静态方法,我们可以称其为“类锁”,即只要有一个线程实例对象获取该锁,其他线程实例对象都需要等待。修饰非静态方法,我们称之为对象锁,即不同的线程实例对象是可以调用同一类下的同步方法。

/**
 * @PackageName com.a.squirrel.synchronize
 * @Author: squirrel
 * @Date: 2018/6/25 10:04
 * @Description: synchronized解析辅助类
 */
public class SynchronizedDescription {

    private String tmpStr;

    private int tmpInt;

    /**
      * @Author squirrel
      * @Description 非静态同步方法
      * @Date 2018/6/25
      * @Param [synchronizedDescription]
      * @return
     **/
    public synchronized void testSynchronizedMethod(SynchronizedDescription synchronizedDescription){
        System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是非静态同步方法=======");
        System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用非静态同步方法时间为:"+getNowTime());
        try {
            Thread.sleep(5000);// 当前线程休眠5s,休眠过程中不会释放锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
      * @Author squirrel
      * @Description 同步代码块
      * @Date 2018/6/25
      * @Param [synchronizedDescription]
      * @return
     **/
    public void testSynchronizedBlockMethod(SynchronizedDescription synchronizedDescription){
        synchronized (synchronizedDescription){// 锁定实例对象
            System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是同步代码块=======");
            System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用同步代码块时间为:"+getNowTime());
            try {
                Thread.sleep(2000);// 当前线程休眠2s,休眠过程中不会释放锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
      * @Author squirrel
      * @Description 静态同步方法
      * @Date 2018/6/25
      * @Param [synchronizedDescription]
      * @return
     **/
    public synchronized static void testSynchronizedStaticMethod(SynchronizedDescription synchronizedDescription){
        System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是静态同步方法=======");
        System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用静态同步方法时间为:"+getNowTime());
        try {
            Thread.sleep(10000);// 当前线程休眠10s,休眠过程中不会释放锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
      * @Author squirrel
      * @Description 获取当前时间
      * @Date 2018/6/25
      * @Param []
      * @return java.lang.String
     **/
    private static String getNowTime(){
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    public SynchronizedDescription(String tmpStr, int tmpInt) {
        this.tmpStr = tmpStr;
        this.tmpInt = tmpInt;
    }

    public String getTmpStr() {
        return tmpStr;
    }

    public void setTmpStr(String tmpStr) {
        this.tmpStr = tmpStr;
    }

    public int getTmpInt() {
        return tmpInt;
    }

    public void setTmpInt(int tmpInt) {
        this.tmpInt = tmpInt;
    }
}
/**
 * @PackageName com.a.squirrel.synchronize
 * @Author: squirrel
 * @Date: 2018/6/25 10:10
 * @Description: 测试类
 */
public class TestSynchronized {

    public static void main(String[] args) {
        // 创建阻塞队列
        final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
        // 创建线程池
        final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,20,60, TimeUnit.SECONDS,queue);
        threadPool.allowCoreThreadTimeOut(true);
        for (int i =0;i<100;i++){
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    final String tmpStr = Thread.currentThread().getName();
                    final String[] split = tmpStr.split("-");
                    int tmpInt = Integer.parseInt(split[split.length-1]);
                    SynchronizedDescription synchronizedDescription = new SynchronizedDescription(tmpStr,tmpInt);
                    // 调用同步代码块
                    synchronizedDescription.testSynchronizedBlockMethod(synchronizedDescription);
                    // 调用非静态同步方法
                    synchronizedDescription.testSynchronizedMethod(synchronizedDescription);
                    // 调用静态同步方法
                    synchronizedDescription.testSynchronizedStaticMethod(synchronizedDescription);
                }
            });
        }
    }
}

运行结果可以验证以上结论:

下面我们变更同步代码块的同步对象:

    /**
      * @Author squirrel
      * @Description 同步代码块
      * @Date 2018/6/25
      * @Param [synchronizedDescription]
      * @return
     **/
    public void testSynchronizedBlockMethod(SynchronizedDescription synchronizedDescription){
        synchronized (SynchronizedDescription.class){// 锁定类对象
            System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:==========我是同步代码块=======");
            System.out.println("线程:"+synchronizedDescription.getTmpInt()+"-->:调用同步代码块时间为:"+getNowTime());
            try {
                Thread.sleep(2000);// 当前线程休眠2s,休眠过程中不会释放锁
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


由上图我们可以得出一个结论,这里借用一张图来说明一下这个结论:

实现原理:

深入理解Java虚拟机:对象在内存中存储的布局可以分为3块区域:对象头,实例数据和对齐填充。

synchronized对象锁其指针指向的是一个monitor对象,每个对象实例都会有一个 monitor,其中monitor可以与对象一起创建销毁,也可以在线程试图获取对象锁时自动生成。在执行monitorenter指令时,首先要尝试获取对象锁,如果这个对象没有被锁定,或者当前线程已经拥有了这个对象的锁,那么就把锁计数器加1,当执行monitorexit指令时,释放锁同时锁计数器也会减1。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!