天天看点

synchronized修饰方法前言一、Synchronized修饰非静态方法二、Synchronized修饰静态方法三、类锁和对象锁的访问是不冲突的四、总结

文章目录

  • 前言
  • 一、Synchronized修饰非静态方法
  • 二、Synchronized修饰静态方法
  • 三、类锁和对象锁的访问是不冲突的
  • 四、总结

前言

直接说结论:

1.Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。

2.Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。

3.对于类锁synchronized static,是通过该类直接调用加类锁的方法,而对象锁是创建对象调用加对象锁的方法,两者访问是不冲突的,对于同一类型锁锁住的方法,同一对象是无法同时访问的.

一、Synchronized修饰非静态方法

Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”。

如果采用形象的比喻就是,对于这个对象可能有很多方法(房间),有一些加了锁(锁门的房间),而这些房间共用一把钥匙,导致当一个被锁方法被访问时,无法访问其他带锁的方法。

但是需要注意:一个对象可以拿一把钥匙,多个对象可以插队执行。

考虑下图代码,想一下会输出什么。

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getTwo();
            }
        }).start();
    }
}

class Number{
    public synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public synchronized void getTwo(){
        System.out.println("two");
    }
}

           

答案是输出one two

因为getOne()虽然要停止2秒,但上了对象锁,getTwo()不能超车(访问),要等getOne()被调用完,把钥匙换回来,才能继续执行

二、Synchronized修饰静态方法

Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”。

类对象只有一个,只在郊外有这一栋别墅,里面的静态方法也被一把锁管着。因为一个类对象只能拿一把锁。

将两个方法都设为static,猜猜会输出什么

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getTwo();
            }
        }).start();
    }
}

class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void getTwo(){
        System.out.println("two");
    }
}

           

输出one two

也可以不new对象直接类对象调用

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getOne();
                Number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getTwo();
                Number.getTwo();
            }
        }).start();
    }
}

class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void getTwo(){
        System.out.println("two");
    }
}
           

答案是 one two

显然,这次我们直接插队进别墅大门失败了,很好地解释了类锁

三、类锁和对象锁的访问是不冲突的

现在我们设定为one静态,two非静态,猜猜会发生什么

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getOne();
                Number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getTwo();
//                Number.getTwo();
            }
        }).start();
    }
}

class Number{
    public static synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public synchronized  void getTwo(){
        System.out.println("two");
    }
}
           

答案是 two one

你开别墅大门,关我别墅内的狗窝什么事?

package JUC_test;

public class TestSyn {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(new Runnable() {
            @Override
            public void run() {
                number.getOne();
//                Number.getOne();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
//                number.getTwo();
                Number.getTwo();
            }
        }).start();
    }
}

class Number{
    public  synchronized void getOne(){
        try {
            Thread.sleep(2000);
            System.out.println("one");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void getTwo(){
        System.out.println("two");
    }
}

           

答案是 two one

同理,你开狗窝大门,关我别墅什么事?

四、总结

对于synchronized修饰方法的调用

我们考虑了

非静态 非静态

静态 静态

静态 非静态

非静态 静态

四种情况,

可以留下思考,如果这些换成两个对象去调用呢?

答案会是什么呢?

two one

one two(有两个实例对象,但只有一个类对象)

two one

two one