synchronized修饰方法

本文详细介绍了Java中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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值