【Java】多线程访问同步方法的7种情况

前言

synchronized有两种用法:对象锁和类锁。
对象锁又分为方法锁(默认锁对象为this)和同步代码块锁。
类锁又分为修饰静态方法的锁和指定为class对象的锁。
类锁的本质是class对象的锁,Java类可能会有很多个对象,但是只有1个class对象。

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

public class SynchronizedObjectMethod3 implements Runnable {
    static SynchronizedObjectMethod3 instance = new SynchronizedObjectMethod3();

    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("finished");
    }
    @Override
    public void run() {
        method();
    }

    public synchronized void method(){
        System.out.println("我的对象锁的方法修饰符形式,我叫" + Thread.currentThread().getName());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "运行结束");
    }
}

此时两个线程争抢同一把锁,故线程为串行执行.
结果为:

我的对象锁的方法修饰符形式,我叫Thread-0
Thread-0运行结束
我的对象锁的方法修饰符形式,我叫Thread-1
Thread-1运行结束
finished

2.两个线程访问两个对象的静态方法

public class SynchronizedObjectCodeBlock2 implements Runnable{
    static SynchronizedObjectCodeBlock2 instance1 = new SynchronizedObjectCodeBlock2();
    static SynchronizedObjectCodeBlock2 instance2 = new SynchronizedObjectCodeBlock2();
    Object lock1 = new Object();
    Object lock2 = new Object();

    @Override
    public void run() {
        synchronized (this){
            System.out.println("我是lock1. 我叫" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() +" lock1部分运行结束.");
        }

//        synchronized (lock2){
//            System.out.println("我是lock2. 我叫" + Thread.currentThread().getName());
//            try {
//                Thread.sleep(3000);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() +" lock2部分运行结束.");
//        }
    }

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

        }
        System.out.println("finished");
    }
}

此时两个线程争抢的是不同的锁,synchronized不起作用.

我是lock1. 我叫Thread-0
我是lock1. 我叫Thread-1
Thread-0 lock1部分运行结束.
Thread-1 lock1部分运行结束.
finished

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

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

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

    public static synchronized void method(){
        System.out.println("我是类锁的第一种形式:static形式.我叫" + 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(instance1);
        Thread t2 = new Thread(instance2);
        t1.start();
        t2.start();
        while(t1.isAlive() || t2.isAlive()){

        }
        System.out.println("finished");
    }
}

结果为:

我是类锁的第一种形式:static形式.我叫Thread-0
Thread-0运行结束.
我是类锁的第一种形式:static形式.我叫Thread-1
Thread-1运行结束.
finished

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

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("finished");
    }
}

一个方法加synchronized修饰不影响另一个方法的并发。非同步方法不受同步方法的影响。

我是加锁的方法.我叫Thread-0
我是没加锁的方法.我叫Thread-1
Thread-0运行结束
Thread-1运行结束
finished

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

public class SynchronizedDifferentMethod7 implements Runnable{
    static SynchronizedDifferentMethod7 instance = new SynchronizedDifferentMethod7();

    @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("finished");
    }

}

此时指认this对象作为锁,对于同一个实例来说,锁是相同的。

我是加锁的方法1.我叫Thread-0
Thread-0运行结束
我是加锁的方法2.我叫Thread-1
Thread-1运行结束
finished

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

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("finished");
    }
}

这两个方法可以并行执行.静态加锁的方法的锁是class对象,非静态加锁的方法的锁对象是this对象.这两个方法不是争抢同一把锁。

我是静态加锁的方法1.我叫Thread-0
我是非静态加锁的方法2.我叫Thread-1
Thread-0运行结束
Thread-1运行结束
finished

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

/**
 * 方法抛异常后,会释放锁
 * 展示不抛出异常前和抛出异常后的对比
 * 一旦抛出了异常
 * 第二个线程会立刻进入同步方法
 * 意味着锁已经释放
 */
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("finished");
    }
}
我是加锁的方法1.我叫Thread-0
Exception in thread "Thread-0" 我是加锁的方法2.我叫Thread-1
java.lang.RuntimeException
	at com.interview.javabasic.thread.SynchronizedException9.method1(SynchronizedException9.java:29)
	at com.interview.javabasic.thread.SynchronizedException9.run(SynchronizedException9.java:16)
	at java.lang.Thread.run(Thread.java:748)
Thread-1运行结束
finished

猜你喜欢

转载自blog.csdn.net/qq_41279172/article/details/104308214