多线程访问同步方法的7种情况(面试常考)

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

public class SynchronizedObjectMethod implements Runnable {
    private static SynchronizedObjectMethod synchronizedObjectMethod = new
            SynchronizedObjectMethod();

    @Override
    public void run() {
        test();
    }

    public synchronized void test(){
        System.out.println("test()方法运行开始" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test()方法运行结束" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(synchronizedObjectMethod);
        Thread t2 = new Thread(synchronizedObjectMethod);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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

代码运行结果:
test()方法运行开始Thread-0
test()方法运行结束Thread-0
test()方法运行开始Thread-1
test()方法运行结束Thread-1
程序运行结束

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

public class SynchronizedObjectMethod implements Runnable {
    private static SynchronizedObjectMethod instance1 = new
            SynchronizedObjectMethod();
    private static SynchronizedObjectMethod instance2 = new
            SynchronizedObjectMethod();

    @Override
    public void run() {
        test();
    }

    public synchronized void test(){
        System.out.println("test()方法运行开始" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test()方法运行结束" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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


代码运行结果:
test()方法运行开始Thread-0
test()方法运行开始Thread-1
test()方法运行结束Thread-0
test()方法运行结束Thread-1
程序运行结束

如果两个线程访问的是两个对象的同步方法,那么这两个线程的运行时互不影响的。

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

public class SynchronizedClassStatic implements Runnable {
    private static SynchronizedClassStatic instance1 = new SynchronizedClassStatic();
    private static SynchronizedClassStatic instance2 = new SynchronizedClassStatic();

    @Override
    public void run() {
        test();
    }

    public synchronized static void test(){
        System.out.println("test()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test()方法运行结束\t" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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

    }
}


代码运行结果:
test()方法运行开始	Thread-0
test()方法运行结束	Thread-0
test()方法运行开始	Thread-1
test()方法运行结束	Thread-1
程序运行结束

4、同时访问同步方法与非同步方法

synchronized关键字只作用于被修饰的方法或代码块上,不会影响到其他没有被synchronized修饰的方法或代码。

public class SynchronizedYesAndNo implements Runnable {
    private static SynchronizedYesAndNo instance = new SynchronizedYesAndNo();
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            test0();
        } else {
            test1();
        }
    }

    public synchronized void test0(){
        System.out.println("synchronized test0()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized test0()方法运行结束\t" + Thread.currentThread().getName());
    }

    public void test1(){
        System.out.println("test1()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("test1()方法运行结束\t" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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

代码运行结果:
synchronized test0()方法运行开始	Thread-0
test1()方法运行开始	Thread-1
synchronized test0()方法运行结束	Thread-0
test1()方法运行结束	Thread-1
程序运行结束

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

就同一个实例而言,多线程在访问该实例的不同的普通同步方法的时候,多线程之间会顺序执行,而不会同时执行,因为synchronized虽然修饰的方法不同,但是他们的锁对象(this)确是同一个,而一个锁在同一时刻只能被一个线程占用。

public class SynchronizedDiffMethod implements Runnable {
    private static SynchronizedDiffMethod instance = new SynchronizedDiffMethod();
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            test0();
        } else {
            test1();
        }
    }

    public synchronized void test0(){
        System.out.println("synchronized test0()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized test0()方法运行结束\t" + Thread.currentThread().getName());
    }

    public synchronized void test1(){
        System.out.println("synchronized test1()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized test1()方法运行结束\t" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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

代码运行结果:
synchronized test0()方法运行开始	Thread-0
synchronized test0()方法运行结束	Thread-0
synchronized test1()方法运行开始	Thread-1
synchronized test1()方法运行结束	Thread-1
程序运行结束

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

两个线程同时访问一个实例的静态synchronized和非静态synchronized方法的时候,两个线程是同时执行的,互不干扰的,原因就在于锁对象不是同一个,一个锁是当前实例对象,一个锁是实例对应类的Class对象。

public class SynchronizedStaticAndNormal implements Runnable {
    private static SynchronizedStaticAndNormal instance = new SynchronizedStaticAndNormal();
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            test0();
        } else {
            test1();
        }
    }

    public synchronized static void test0(){
        System.out.println("synchronized static test0()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized static test0()方法运行结束\t" + Thread.currentThread().getName());
    }

    public synchronized void test1(){
        System.out.println("synchronized test1()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized test1()方法运行结束\t" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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

代码运行结果:
synchronized static test0()方法运行开始	Thread-0
synchronized test1()方法运行开始	Thread-1
synchronized test1()方法运行结束	Thread-1
synchronized static test0()方法运行结束	Thread-0
程序运行结束

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

public class SynchronizedException implements Runnable {
    private static SynchronizedException instance = new SynchronizedException();
    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("Thread-0")){
            test0();
        } else {
            test1();
        }
    }

    public synchronized void test0(){
        System.out.println("synchronized static test0()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        throw new RuntimeException();
        //System.out.println("synchronized static test0()方法运行结束\t" + Thread.currentThread().getName());
    }

    public synchronized void test1(){
        System.out.println("synchronized test1()方法运行开始\t" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("synchronized test1()方法运行结束\t" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(instance);
        Thread t2 = new Thread(instance);
        t1.start();
        t2.start();
        //线程的isAlive()方法的功能是判断当前线程是否处于活动状态(就绪状态或者运行状态)
        //下面的循环会在两个线程都运行结束后 结束
        while(t1.isAlive() || t2.isAlive()){

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

代码运行结果:
synchronized static test0()方法运行开始	Thread-0
Exception in thread "Thread-0" synchronized test1()方法运行开始	Thread-1
java.lang.RuntimeException
	at com.bxp.thread.SynchronizedException.test0(SynchronizedException.java:21)
	at com.bxp.thread.SynchronizedException.run(SynchronizedException.java:8)
	at java.lang.Thread.run(Thread.java:748)
synchronized test1()方法运行结束	Thread-1
程序运行结束

总结:

1)一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应第1、5种情况)

2)每个实例都对应的有自己的一把锁,不同实例之间是互不影响的。例外,锁对象是*.class以及synchronized修饰的是static方法的时候,所有对象共用同一把锁(对应第2、3、4、6种情况)

3)无论方法是正常执行完毕还是方法抛出异常,都会释放锁(对应第7种情况)

补充:当线程进入到一个被synchronized修饰的方法A,A方法调用了没有被synchronized修饰的方法B,线程在运行B方法的时候,是没有线程安全的,此时其他的线程也可以调用方法B,因为方法B没有被synchronized修饰,不是线程安全的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值