多线程之对象及变量的并发访问(四) - synchronized 方法与锁对象

一、前述

我们一直都说,线程锁住的都是对象,那本文就来证明下究竟是对象还是其他的

二、synchronized 方法与锁对象

public class SynTest02 {
    public void testA(){
        try {
            System.out.println("testA begin threadname = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("testA end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class ThreadA extends Thread{
    private SynTest02 synTest02;
    public ThreadA(SynTest02 synTest02){
        super();
        this.synTest02 = synTest02;
    }
    @Override
    public void run(){
        super.run();
        synTest02.testA();
    }
}
public class ThreadB extends Thread{
    private SynTest02 synTest02;
    public ThreadB(SynTest02 synTest02){
        super();
        this.synTest02 = synTest02;
    }
    @Override
    public void run(){
        super.run();
        synTest02.testA();
    }
}
public class Run {
    public static void main(String[] args) {
        SynTest02 synTest02 = new SynTest02();
        ThreadA a = new ThreadA(synTest02);
        a.setName("a");
        ThreadB b = new ThreadB(synTest02);
        b.setName("b");
        a.start();
        b.start();
    }
}
运行结果:
testA begin threadname = a
testA begin threadname = b
testA end
testA end

从运行结果可以看到,异步打印,没有同步的过程,a 线程还没跑完,没有打印 end,b 线程就开始进入了方法,也就是说两个线程在抢夺对象执行方法

将方法改为 synchronized 修饰,代码如下:

public class SynTest02 {
    public synchronized void testA(){
        try {
            System.out.println("testA begin threadname = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("testA end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
运行结果:
testA begin threadname = a
testA end
testA begin threadname = b
testA end

1、运行结果可以看到,a 线程进入方法以后,获取了对象锁,执行第一个输出,然后睡眠 5 s ,继续执行 end 的输出,紧接着 b 线程进入方法,执行代码,可以得到:是同步在进行的,两个线程排队运行。

2、学习和应用 synchronized 的时候,我们要记住,调用关键字 synchronized 修饰的时候,要记住,只有读写访问共享的资源的时候,才需要同步,如果不是共享的资源,就没必要同步竞争

3、看到这里,可能又会有疑问,该对象所属的类里面的其他方法,被访问调用的时候哦,是什么效果呢?怎么查看锁对象的效果呢,这里来看看另外一段代码:

public class SynTest02 {
    public synchronized void testA(){
        try {
            System.out.println("testA begin threadname = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("testA end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    public void testB(){
        try {
            System.out.println("testB begin threadname = " + Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("testB end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

在类中加上一个非同步的方法 testB ,然后 ThreadB 里面调用 testB 方法:

public class ThreadB extends Thread{
    private SynTest02 synTest02;
    public ThreadB(SynTest02 synTest02){
        super();
        this.synTest02 = synTest02;
    }
    @Override
    public void run(){
        super.run();
        synTest02.testB();
    }
}

运行结果:
testA begin threadname = abegintime = 1561198111126
testB begin threadname = bbegintime = 1561198111126
testA end , endtime = 1561198116127
testB end , endtime = 1561198116127

1、从运行结果可以看出,虽然线程 A 先拥有了该对象的锁,但是线程 B 还是可以异步的调用该对象所属里面的非同步方法,也就是没有加 synchronized 关键字修饰的方法

2、接下来将 testB 也改为 synchronized 关键字修饰

public class SynTest02 {
    public synchronized void testA(){
        try {
            System.out.println("testA begin threadname = " + Thread.currentThread().getName()+"begintime = "+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("testA end , endtime = " + System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    public synchronized void testB(){
        try {
            System.out.println("testB begin threadname = " + Thread.currentThread().getName()+"begintime = "+System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("testB end , endtime = "+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
运行结果:
testA begin threadname = abegintime = 1561198343034
testA end , endtime = 1561198348036
testB begin threadname = bbegintime = 1561198348036
testB end , endtime = 1561198353036

运行结果可以i看出来,线程 A 先获取到对象的锁以后,线程 B 被阻塞,处于等待状态,因为两个线程对同一个对象访问的时候,访问同步方法,会将对象锁住,不允许其他的线程访问,也就是同步的一个过程

总结:
当线程 A、B 同时通过一个对象访问一个方法的时候,如果这个方法是被关键字 synchronized 修饰的,那么这个对象就会被锁住,只允许当前线程操作访问,如果访问不是被它修饰的方法,那么就不会被锁住,这样其他线程也可以访问它的非同步方法,异步进行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值