Java多线程并发synchronized锁

一、基本概念

        synchronized 是由 monitorenter / monitorexit 的指令实现的。Java 6之前完全是依赖操作系统的互斥锁。现在的JDK中,JVM对此进行了改进,提供了三种 monitor 的实现,偏斜锁(Biased Lock),轻量级锁,重量级锁 很大程度上的提高了性能。

        升级降级:是JVM 对synchronized的优化,检测到不同的竞争状况,JVM会自动的切换到适合的锁,没有竞争出现的时候,默认出现的是 偏斜锁,JVM会采用CAS (Compare and swap)的方式,  在对象的头上的Mark Word 部分设置 线程的ID ,表示这个对象偏向于当前线程,并不涉及真正的互斥锁,使用偏斜锁可以降低无竞争的开销。若别的线程想锁定某个已经被偏斜过的对象。JVM就需要撤销偏斜锁。切换到轻量级锁实现,轻量级锁依赖于CAS操作Mark Word 来试图获得锁,若重试成功,就使用普通的轻量级锁,否则就使用重量级锁。降级也是确实会发生的,当JVM 进行入安全点(SafePoint)的时候,会检查是否有闲置的monitor来进行降级。

二、使用场景

    //同步的方法
    pubilc synchronized void test() {
    
    }
    //静态 
    pubilc static synchronized void test() {
    
    }
    //同步代码块上
    public void test() {
         synchronized(obj) {
              System.out.println("===");
         }
    }

三、synxheonized (this) 和 synchronized(object) 区别

 

       synchronized(object) 是包含  synchronized(this)的,

        1.当两个线程同时执行一个 synchronized 的同步代码块的时候 ,同一个时间片内只允许执行一个线程, 另一个线程必须等到当前的线程执行完毕后才能执行。

        2.当一个线程执行 synchronized 同步代码块的时候,就获得了对象锁。另一个线程可以执行 非 同步的方法,若另一个线程执行 同步代码快时,会被阻塞。

        synchronized method :会获得所有的 synchronized 的对象锁,,也就是说一个线程在执行 同步代码块的时候,影响了其他线程对同步代码块的访问。

        在 静态方法前加 synchronized :静态方法属于这个类,获取到的锁属于类的锁

        在非静态方法前加 synchronized :属于当前对象的锁。

四、案例分析

第一个案例

    Thread01 t01 = new Thread01(); // 
    System.out.println("synchronized 关键字使用 \n" +"--------------------------");
    Thread ta = new Thread(t01,"A");
    Thread tb = new Thread(t01,"B");
    //谁抢到了 cpu 的执行权 ,谁就执行
    ta.start();
    tb.start();
    
    private class Thread01 implements Runnable{
        @Override
        public void run() {
            synchronized (this) {
                for(int i=0;i<3;i++){
                    System.out.println(Thread.currentThread().getName()+" synchronized loop "+i);
                }
            }
        }
    }
    执行结果:
    synchronized 关键字使用
    --------------------------
    B synchronized loop 0
    B synchronized loop 1
    B synchronized loop 2
    A synchronized loop 0
    A synchronized loop 1
    A synchronized loop 2

第二个案例

    
    // 当一个线程在执行 同步代码块的时候,其他的线程必须等当前的线程执行完毕后才能执行。因为是非公平锁,其他的线程会争抢这个锁。
    System.out.println("synchronized 关键字使用 \n" +"--------------------------");
    Thread t02A = new Thread(new Runnable() {
        @Override
        public void run() {
            method01();
        }
    },"A");
    Thread t02B = new Thread(new Runnable() {
    
        @Override
        public void run() {
            method02();
        }
    },"B");
    Thread t02C = new Thread(new Runnable() {
        @Override
        public void run() {
            method3();
        }
    },"C");
    t02A.start();
    t02B.start();
    t02C.start();

//-------------
    public void method01(){
        synchronized (this) {
            int i=0;
            while(i++ < 3){
                System.out.println(Thread.currentThread().getName() +":"+ i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public void method02(){
        //第2种方式:当一个线程访问object的一个synchronized(this)同步代码块时,
        //其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
        synchronized (this) {
            int j=0;
            while(j++ < 3){
                System.out.println(Thread.currentThread().getName() +":"+ j);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    /*
     * 当一个线程访问object的一个synchronized(this)同步代码块时,
     * 它就获得了这个object的对象锁。
     * 结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
     */
    public synchronized void method3(){
        int k=0;
        while(k++ < 3){
            System.out.println(Thread.currentThread().getName() +":"+ k);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    执行结果:
    synchronized 关键字使用
    --------------------------
    B:1
    B:2
    B:3
    C:1
    C:2
    C:3
    A:1
    A:2
    A:3

第三个例子

    final InnerObject innerObj = new InnerObject();// 对象锁
    System.out.println("synchronized 关键字使用 \n" +"--------------------------");
    Thread t03A = new Thread(new Runnable() {
        @Override
        public void run() {
            outerMethod01(innerObj);
        }
    },"A");
    Thread t03B = new Thread(new Runnable() {
        @Override
        public void run() {
            outerMethod02(innerObj);
        }
    },"B");
    t03A.start();
    t03B.start();
    
    class InnerObject{
        private void innerMethod01(){
            int i=0;
            while(i++ < 3){
                System.out.println(Thread.currentThread().getName() +":"+ i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    
        private void innerMethod02(){
            int j=0;
            while(j++ < 3){
                System.out.println(Thread.currentThread().getName() +":"+ j);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     * 外部类方法1
     */
    private void outerMethod01(InnerObject innerObj){
        synchronized (innerObj) {
            innerObj.innerMethod01();
        }
    }
    
    /**
     * 外部类方法2
     */
    private void outerMethod02(InnerObject innerObj){
        innerObj.innerMethod02();
    }
    
    执行结果:
    synchronized 关键字使用
    --------------------------
    A:1
    B:1
    B:2
    A:2
    B:3
    A:3

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值