Java多线程(三)------深度解析:synchronized修饰方法与代码块的区别

        初学多线程,肯定会接触同步。我们知道synchronized关键词可以修饰代码块,也可以修饰方法。那么具体修饰有什么区别呢?

        一、含义

        关于含义的资料随便一搜就是一大把,我在这里列出一篇文章的介绍:

  •  synchronized 是同步锁,用来实现互斥同步。

  • 在 Java 中,关键字 synchronized 可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作)。

  • synchronized 还可以保证一个线程的变化(主要是共享数据的变化)被其他线程所看到(保证可见性,完全可以替代 volatile 功能,但是 volatile 更轻量,还是要分场景使用)。

        参考链接:https://www.cnblogs.com/weixuqin/p/11429005.html

        二、用法

        synchronized可以修饰代码块、修饰静态方法、修饰非静态方法。

        2.1 修饰代码块

        修饰代码块的用法,是最常见的一种写法,其中的需要重点理解的是锁的含义。我们通过查看资料得知synchronized (A)括号肿的A有时候会用"this",有时候会用我们自己定义的一个对象。那么他们直接有什么区别呢?

        如下图代码,用this锁。

class TestDiffObj implements Runnable {
    @Override
    public void run() {
        obj2();
    }    
    public void obj2() {
        synchronized (this) {//这个this就是指当前对象(类的实例)
            System.out.println(this.hashCode());
            int i = 5;
            while (i-- > 0) {
                System.out.println(Thread.currentThread().getName() + " : " + i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ie) {
                }
            }
        }
    }
}

       ① this:代表的是当前对象,也就是类的实例。

        我们知道,下述新建了两个当前类的实例对象。

 TestDiffObj testDiffObj1 = new TestDiffObj();
 TestDiffObj testDiffObj2 = new TestDiffObj();

        如果,我们新建的线程用不同的对象实例,那么start后,就会有两个线程同时执行上述代码中的obj2()方法。虽然加锁了,但是锁对象不同,不能达到同步的目的,此时不会存在阻塞。

Thread thread1 = new Thread(testDiffObj1);
Thread thread2=new Thread(testDiffObj2);
thread1.start();
thread2.start();

       

        但是,如果我们新建的线程用同一个实例对象,那么执行start()对象后,由于锁对象一致,那么会先执行完获得锁对象的线程,然后再执行另外一个线程。此时会有阻塞 

Thread thread1 = new Thread(testDiffObj1);
Thread thread2 = new Thread(testDiffObj1);
thread1.start();
thread2.start();

        ② 自定义对象

        使用自定义对象作为锁,其实和this本质是相同的。只要保证使用到的锁对象唯一,那么就能达到同步的目的,即会产生阻塞线程。

 

        如果锁对象不唯一,则线程各自执行,不会产生阻塞。

         2.2 修饰静态方法

        修饰静态方法时,此时锁对象为所在类,即TestDiffObj .class即为锁。

class TestDiffObj implements Runnable {
    Object object = new Object();
    @Override
    public void run() {
        obj3();
    }
    public static synchronized void obj3() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }

}

         由于类锁是唯一的,此时不管新建的线程是否是同一个类的实例对象,执行起来都是同步

        2.3 修饰非静态方法

        修饰非静态方法,其实与使用this关键字的效果是相同的。

class TestDiffObj implements Runnable {
    Object object = new Object();
    @Override
    public void run() {
        obj4();
    }

    public synchronized void obj4() {
        int i = 5;
        while (i-- > 0) {
            System.out.println(Thread.currentThread().getName() + " : " + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException ie) {
            }
        }
    }
}

 

         三、写在最后

        其实,Synchronized不管修饰代码块,静态方法还是非静态方法,最关键的还是搞清楚锁对象是否是一致的。

        如果线程使用的锁一致,即多线程访问的是同一个对象,则能达到同步的效果;

        否则线程则各自执行,不存在阻塞。

        

        -----上述仅为我初学多线程的个人理解,欢迎小伙伴们一起交流