Java微服务架构师_Java 并发编程_002

本文详细介绍了Java中synchronized的三种使用方式:同步方法、静态同步方法和同步代码块,并通过示例展示了它们在共享变量场景中的应用,探讨了非静态同步方法、静态同步方法之间的竞态条件和锁的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从我们熟悉的同步锁了解多线程使用方式

synchronized几种使用方式

演示 (共享变量)同步锁的使用场景: 同步方法、 静态同步方法 、同步代码块

package com.allen.base.day02;

import java.util.Random;

public class SynchronizedDemo {
    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.OneClass();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.OneClass();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }

    public synchronized void first() throws InterruptedException {
        double random = Math.random();
        System.out.println(random + " first======start=======>");
        Thread.sleep(5000);
        System.out.println(random + " first======end=======>");
    }

    public synchronized void second() throws InterruptedException {
        System.out.println("second=====start========>");
        Thread.sleep(5000);
        System.out.println("second======end=======>");
    }

    public void one() throws InterruptedException {
        double random = Math.random();
        System.out.println("进入线程===========。。。。" + random);
        synchronized (this) {
            System.out.println(random + " one=======start======>  ");
            Thread.sleep(5000);
            System.out.println(random + " one=======end======>  ");
        }
    }

    public synchronized void two() throws InterruptedException {
        synchronized (this) {
            System.out.println("two======start=======>");
            Thread.sleep(5000);
            System.out.println("two======end=======>");
        }
    }

    public void OneClass() throws InterruptedException {
        double random = Math.random();
        System.out.println(random);
        synchronized (SynchronizedDemo.class) {
            System.out.println(random + " OneClass======start=======>");
            Thread.sleep(5000);
            System.out.println(random + " OneClass======end=======>");
        }
    }
}

几种测试场景:

1、非静态同步方法

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }
    
    public synchronized void twoClass1() throws InterruptedException {
        System.out.println("twoClass1======start=======>");
        Thread.sleep(5000);
        System.out.println("twoClass1======end=======>");
    }

2、静态同步方法

 public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }
    
    public synchronized static void twoClass2() throws InterruptedException {
        System.out.println("twoClass2======start=======>");
        Thread.sleep(5000);
        System.out.println("twoClass2======end=======>");
    }

3、同步代码块

 public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.one();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.one();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }

    public void one() throws InterruptedException {
        double random = Math.random();
        System.out.println("进入线程===========。。。。" + random);
        synchronized (this) {
            System.out.println(random + " one=======start======>  ");
            Thread.sleep(5000);
            System.out.println(random + " one=======end======>  ");
        }
    }

组合场景:
1、静态同步方法与非静态同步方法

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }
    
    public synchronized void twoClass1() throws InterruptedException {
        System.out.println("twoClass1======start=======>");
        Thread.sleep(5000);
        System.out.println("twoClass1======end=======>");
    }

    public synchronized static void twoClass2() throws InterruptedException {
        System.out.println("twoClass2======start=======>");
        Thread.sleep(5000);
        System.out.println("twoClass2======end=======>");
    }

2、非静态同步方法与同步代码块

public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass1();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.one();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }
    
    public void one() throws InterruptedException {
        double random = Math.random();
        System.out.println("进入线程===========。。。。" + random);
        synchronized (this) {
            System.out.println(random + " one=======start======>  ");
            Thread.sleep(5000);
            System.out.println(random + " one=======end======>  ");
        }
    }
    public synchronized void twoClass1() throws InterruptedException {
        System.out.println("twoClass1======start=======>");
        Thread.sleep(5000);
        System.out.println("twoClass1======end=======>");
    }

3、静态同步方法与同步代码块

    public static void main(String[] args) {
        SynchronizedDemo demo = new SynchronizedDemo();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.one();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    demo.twoClass2();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });


        threadB.start();
        threadA.start();
    }
    
    public void one() throws InterruptedException {
        double random = Math.random();
        System.out.println("进入线程===========。。。。" + random);
        synchronized (this) {
            System.out.println(random + " one=======start======>  ");
            Thread.sleep(5000);
            System.out.println(random + " one=======end======>  ");
        }
    }
    
    public synchronized static void twoClass2() throws InterruptedException {
        System.out.println("twoClass2======start=======>");
        Thread.sleep(5000);
        System.out.println("twoClass2======end=======>");
    }

总结

Java中的每一个对象都可以作为锁,
具体表现为以下3种形式
对于普通同步方法,锁是当前实例对象
对于静态同步方法,锁是当前类的Class对象
对于同步代码块,锁是synchronized括号中配置的对象

如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取方法释放锁后才能获取锁

所有的静态同步方法用的也是同一把锁:类对象本身
非静态同步方法与静态同步方法对应的锁是两个不同对象,所以静态同步方法非静态同步方法之间是不会有竞态条件的。
但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,
不管是同一个实例对象的静态同步方法之间,还是不同实例对象的静态同步方法之间,只要他们是同一个类的实例对象 。

synchronized修饰方法使用的锁是当前对象this锁,
synchronized修饰静态方法使用的锁是当前类的字节码文件。
从JVM规范中可以看到synchronized在JVM中的实现原理,JVM基于进入与退出Monitor对象来实现方法的同步与代码块的同步,但两者实现细节不同,代码块同步是使用monitorenter和monitorexit指令实现的,而方法的同步是使用另一种方式实现的,细节在JVM规范中没有详细说明,但是,方法的同步同样可以使用这2个指令实现。
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每一个monitorenter必须对应一个monitorexit对应,任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态,线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即获取对象的锁。synchronized用的锁是在java对象的头里(Class字节码格式中的头部信息)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coder_Boy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值