地表最强教程:Synchronized关键字深析(一)

开课吧开课吧锤锤2021-03-18 09:56

    Java编程语言是一种简单、面向对象、分布式、解释型、健壮安全、与系统无关、可移植、高性能、多线程和动态的语言。如今Java已经广泛应用于各个领域的编程开发。

    一、synchronized基础

    synchronized关键字在需要原子性、可见性和有序性这三种特性的时候都可以作为其中一种解决方案,看起来是“万能”的。的确,大部分并发控制操作都能使用synchronized来完成。在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着JavaSE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了JavaSE1.6中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁,以及锁的存储结构和升级过程。

    1.1synchronized的使用

修饰目标
方法 实例方法 当前实例对象(即方法调用者)
静态方法 类对象
代码块 this 当前实例对象(即方法调用者)
class对象 类对象
任意Object对象 任意示例对象

    1.1示例

public class Synchronized {
    //synchronized关键字可放于方法返回值前任意位置,本示例应当注意到sleep()不会释放对监视器的锁定
    //实例方法
    public synchronized void instanceMethod() {
        for (int i = 0; i < 5; i++) {
            System.out.println("instanceMethod");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //静态方法
    public synchronized static void staticMethod() {
        for (int i = 0; i < 5; i++) {
            System.out.println("staticMethod");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void thisMethod() {
        //this对象
        synchronized (this) {
            for (int i = 0; i < 5; i++) {
                System.out.println("thisMethod");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void classMethod() {
        //class对象
        synchronized (Synchronized.class) {
            for (int i = 0; i < 5; i++) {
                System.out.println("classMethod");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void anyObject() {
        //任意对象
        synchronized ("anything") {
            for (int i = 0; i < 5; i++) {
                System.out.println("anyObject");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

    1.2验证

    1.2.1普通方法和代码块中使用this是同一个监视器(锁),即某个具体调用该代码的对象

 public static void main(String[] args) {
        Synchronized syn = new Synchronized();
        for (int i = 0; i < 10; i++) {
            new Thread() {
                @Override
                public void run() {
                    syn.thisMethod();
                }
            }.start();
            new Thread() {
                @Override
                public void run() {
                    syn.instanceMethod();
                }
            }.start();
        }
    }

    我们会发现输出结果总是以5个为最小单位交替出现,证明sychronized(this)和在实例方法上使用synchronized使用的是同一监视器。如果去掉任一方法上的synchronized或者全部去掉,则会出现instanceMethod和thisMethod无规律的交替输出。

    1.2.2静态方法和代码块中使用该类的class对象是同一个监视器,任何该类的对象调用该段代码时都是在争夺同一个监视器的锁定

 public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Synchronized syn = new Synchronized();
            new Thread() {
                @Override
                public void run() {
                    syn.staticMethod();
                }
            }.start();
            new Thread() {
                @Override
                public void run() {
                    syn.classMethod();
                }
            }.start();

        }
    }

    输出以5个为最小单位交替出现,证明两段代码是同一把锁,如果去掉任一synchronnized则会无规律交替出现。

    1.2、synchronized的特点

    可重入性

    当代码段执行结束或出现异常后会自动释放对监视器的锁定

    是非公平锁,在等待获取锁的过程中不可被中断

    synchronized的内存语义

    互斥性,被synchronized修饰的方法同时只能由一个线程执行

    以上内容由开课吧老师Java新生代提供,更多Java教程尽在开课吧广场Java教程频道。

有用
分享