你不知道的Synchronized

众所周知,synchronized关键字是Java语言中一种重要的同步机制,它既可以修饰方法,也可以修饰代码块。synchronized使用了对象的内部锁,使得每个线程在访问临界区时要先获得锁,保证了线程的安全。在JDK的早期版本中,synchronized的性能远远低于重入锁,但从JDK 6.0开始对synchronized进行了大量的优化,使得二者的性能差距不大。因此,在并发量并不是很高的情况下,使用synchronized完全可以满足要求。
相信读者对synchronized的用法都有一定了解,因此,这里说一些关于synchronized的细节:

1.对象锁和类锁

当synchronized修饰一个实例方法时,该方法的锁为this,即对象锁。
当synchronized修饰一个静态方法时,该方法的锁为该类的Class对象,即类锁。
可以根据实际的业务需求,选择锁的级别。

2. synchronized的锁重入性

synchronized关键字拥有锁重入的功能,也就是在使用synchronized时,当一个线程获得了一个对象的锁后,再次请求次对象时可以再次获得对象锁。示例如下:

public class ReentrantTest {

    public static void main(String[] args) {
        Thread th = new Thread(new MyTask());
        th.start();

    }

}

class MyTask implements Runnable{

    public synchronized void run() {
        System.out.println("MyTask start...");

        //已获得对象锁的线程,可再次请求锁
        fun1();

    }

    public synchronized void fun1(){
        System.out.println("invoke fun1...");
        fun2();
    }

    public synchronized void fun2(){
        System.out.println("invoke fun2...");
    }

}

运行结果:

MyTask start...
invoke fun1...
invoke fun2...

3.继承关系下的同步性

在创建了一个子类对象时,该对象内部维护了一个父类的对象。根据synchronized的锁重入性,子类的同步方法可以再次调用父类的同步方法,保证线程安全问题。示例如下:

public class SynExtends {

    //父类
    public static class Super{
        public int count = 10;

        //父类的同步方法
        public synchronized void SupOperation(){
            System.out.println("Super: count=" + count--);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //子类
    public static class Sub extends Super{

        //子类的同步方法
        public synchronized void SubOperation(){
            while (count > 0){
                System.out.println("Sub: count=" + count--);

                //调用父类的同步方法
                super.SupOperation();
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {         

            public void run() {
                Sub sub = new Sub();
                sub.SubOperation();

            }
        }).start();
    }
}

运行结果:

Sub: count=10
Super: count=9
Sub: count=8
Super: count=7
Sub: count=6
Super: count=5
Sub: count=4
Super: count=3
Sub: count=2
Super: count=1

由此可见,可以通过同时在父类和子类上使用synchronized 来保证继承关系下的线程安全。

猜你喜欢

转载自blog.csdn.net/weixin_34452850/article/details/53182929