synchronized修饰不同资源

内置锁:
            每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。

互斥锁:
            内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

1.synchronized修饰普通方法:

锁住对象的实例,并不会锁住整个类的实例。

package com.xdclass.safe;

/**
 * @author sqz
 * @Description: 深入理解synchronized关键字
 * @date 2019/8/6 13:39
 */
public class SynDemo {
    //锁住对象的实例,并不会锁住整个类的实例
    public synchronized void out() throws InterruptedException {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(5000L);
    }

    public static void main(String[] args) {
        SynDemo synDemo = new SynDemo();
        SynDemo synDemo2 = new SynDemo();
        new Thread(()->{
            try {
                synDemo.out();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                synDemo2.out();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

测试结果:由此可见,synchronized修饰普通方法并不会锁住整个类,只会锁住单个实例,这里new了两个实例,两个线程访问普通out()方法,分别锁住各自实例的方法,并不会互相干扰 

2.synchronized修饰静态方法:

锁住整个类

package com.xdclass.safe;

/**
 * @author sqz
 * @Description: 深入理解synchronized关键字
 * @date 2019/8/6 13:39
 */
public class SynDemo {
    //锁住对象的实例,并不会锁住整个类的实例
//    public synchronized void out() throws InterruptedException {
//        System.out.println(Thread.currentThread().getName());
//        Thread.sleep(5000L);
//    }

    //锁住对象的实例,并不会锁住整个类的实例
    public static synchronized void outStatic() throws InterruptedException {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(5000L);
    }

    public static void main(String[] args) {
        new Thread(()->{
            try {
                SynDemo.outStatic();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                SynDemo.outStatic();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

如上实例,在打印了Thread-0之后隔了5秒才打印Thread-1,如果等待很长很长时间,那么后一个线程只能等待,也就是说,一个类如果有一个使用synchronized修饰了的静态方法,那么整个类都会被锁住,这整个类里面不管有多少个synchronized修饰的方法,锁已经被一个线程获取了,其他线程只能等待,所以一般在开发中最好不要用synchronized修饰静态方法,这是一个很危险的操作,他会导致其他线程一直在等待这个锁

3.修饰代码块 

 锁住一个对象 synchronized (lock) 即synchronized后面括号里的内容,这样并不会锁住一个方法或者整个类
 

package com.xdclass.safe;

/**
 * @author sqz
 * @Description: 深入理解synchronized关键字
 * @date 2019/8/6 13:39
 */
public class SynDemo {
    private Object lock = new Object();
    //修饰代码块
    public void myOut()  {
        synchronized (lock){
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynDemo synDemo = new SynDemo();
        new Thread(()->{
            synDemo.myOut();
        }).start();
        new Thread(()->{
            synDemo.myOut();
        }).start();
    }
}

如上图所示,在Thread-0打印5秒之后Thread-1才会打印,因为new了一个synDemo对象, 只有lock一个实例,两个线程start(),只有一个线程能够持有锁,等待一个线程执行完释放了锁另外一个才能获取到。如果new 两个synDemo实例,那么就会有两个lock对象,如果两个线程分别调用myOut()方法,那么会差不多时间打印,因为两个实例互不干涉。如下图所示:

package com.xdclass.safe;

/**
 * @author sqz
 * @Description: 深入理解synchronized关键字
 * @date 2019/8/6 13:39
 */
public class SynDemo {

    private Object lock = new Object();
    //修饰代码块
    public void myOut()  {
        synchronized (lock){
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(5000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynDemo synDemo = new SynDemo();
        SynDemo synDemo2 = new SynDemo();
        new Thread(()->{
            synDemo.myOut();
        }).start();
        new Thread(()->{
            synDemo2.myOut();
        }).start();
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值