Java高并发之魂-synchronized深度解析 学习笔记(3)- 多线程访问同步方法的7种情况(面试)

1 两个线程同时访问一个对象的同步方法

  • synchronized 起作用

2 两个线程访问的是两个对象的同步方法

  • synchronized 不起作用

3 两个线程访问的是 synchronized 的静态方法

  • synchronized 起作用

4 同时访问同步方法和非同步方法

  • synchronized 不会影响其他方法,即非同步方法不受影响
/**
 * @Description 同步方法和非同步方法
 * @Author tzb
 * @Date 2021/1/8 15:52
 * @Version 1.0
 **/
public class SynchronizedYesAndNo6 implements Runnable {

    static SynchronizedYesAndNo6 instance = new SynchronizedYesAndNo6();


    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method1();
        } else {
            method2();
        }
    }

    public synchronized void method1() {
        System.out.println("我是加锁的方法,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public void method2() {
        System.out.println("我是没有加锁的方法,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        System.out.println("运行结束");

    }
}

在这里插入图片描述

5 访问同一个对象的不同的普通同步方法

  • 两个 synchronized 拿到的都是 instance 的 this
  • 程序串行运行
/**
 * @Description  同时访问一个类的不同的普通同步方法
 * @Author tzb
 * @Date 2021/1/8 16:53
 * @Version 1.0
 **/
public class SynchronizedDiffMethod7 implements Runnable {

    static SynchronizedDiffMethod7 instance = new SynchronizedDiffMethod7();


    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method1();
        } else {
            method2();
        }
    }

    public synchronized void method1() {
        System.out.println("我是加锁的方法1,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public synchronized void method2() {
        System.out.println("我是加锁的方法2,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        System.out.println("运行结束");

    }
}

在这里插入图片描述

6 同时访问静态 synchronized 和 非静态 synchroinzed 方法

  • 拿到的锁是不一样的,可以同时运行
public class SynchronizedStaticAndNormal8 implements Runnable {

    static SynchronizedStaticAndNormal8 instance = new SynchronizedStaticAndNormal8();

    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method1();
        } else {
            method2();
        }
    }

    public synchronized static void method1() {
        System.out.println("我是静态加锁的方法1,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public synchronized void method2() {
        System.out.println("我是非静态加锁的方法2,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        System.out.println("运行结束");

    }
}

在这里插入图片描述

7 方法抛出异常后,会释放锁

一旦抛出了异常,第二个线程会立刻进入同步方法,意味着锁已经释放

/**
 * @Description 方法抛出异常,释放锁
 * @Author tzb
 * @Date 2021/1/8 17:07
 * @Version 1.0
 **/
public class SynchronizedException9 implements Runnable {

    static SynchronizedException9 instance = new SynchronizedException9();

    @Override
    public void run() {
        if (Thread.currentThread().getName().equals("Thread-0")) {
            method1();
        } else {
            method2();
        }
    }

    public synchronized void method1() {
        System.out.println("我是加锁的方法1,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 不要求强制捕获
        throw new RuntimeException();

        //System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public synchronized void method2() {
        System.out.println("我是加锁的方法2,我叫 " + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + " 运行结束");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        while (t1.isAlive() || t2.isAlive()) {

        }
        System.out.println("运行结束");

    }

}

在这里插入图片描述

8 7种情况的总结:核心思想

  1. 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(情况1、5)
  2. 每个实例都对应有自己的一把锁,不同实例之间互不影响。例外:锁对象是 *.class 以及 synchronized 修饰的是 static 方法的时候,所有的对象共用同一把类锁。(情况2、3、4、6)
  3. 无论方法正常执行完毕或者抛出异常,都会释放锁

一个被synchronized修饰的方法调用了没有被同步修饰的方法还是线程安全的么?

  • 不是线程安全了,因为调用的那个方法没有被修饰,其本身是可以被多个线程同时调用的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值