synchronized用法总结(4个案例进行说明)

由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。
需要明确的几个问题:

1、synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
2、无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
每个对象只有一个锁(lock)与之相关联。
3、实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
(这段文字来源于https://www.jianshu.com/p/ea9a482ece5f)
4、synchronized关键字出现在实例方法上锁住的是对象,即对象锁;synchronized关键字出现在静态方法上锁住的是类,即类锁;对象锁可以有多个,new几个对象就有几个对象锁,但是类锁只有一把。

例一:

public class Main {
    public static void main(String[] args) {
        //new了一个对象所以只有一个对象锁
        myClass m = new myClass();
        Thread t1 = new Thread(new myThread(m));
        Thread t2 = new Thread(new myThread(m));

        t1.setName("t1");
        t2.setName("t2");

        t1.start();
        try {  //保证t1先执行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.start();
    }
}
class myClass{
    //synchronized出现在实例方法上表示锁住的就是this,即整个方法体都需要线程同步
    public synchronized void doSome(){
        System.out.println("doSome begin...");
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over...");
    }

    public void doOther(){
        System.out.println("doOther begin...");
        System.out.println("doOther over...");
    }
}

class myThread implements Runnable {
    private myClass m;

    public myThread(myClass m) {
        this.m = m;
    }

    @Override
    public void run() {
        if(Thread.currentThread().getName().equals("t1")){
            m.doSome();
        }
        if(Thread.currentThread().getName().equals("t2")){
            m.doOther();
        }
    }
}

结果:
在这里插入图片描述
总结:
在t1先执行的情况下t2并没有等待t1执行结束后才执行,因为t2线程执行的方法没有用到线程同步,所以执行前不需要获得对象锁就可以执行;
例二:

//把上面的doOther方法加上synchronized关键字
public synchronized void doOther(){
        System.out.println("doOther begin...");
        System.out.println("doOther over...");
    }

结果:
在这里插入图片描述
总结:t2线程执行的方法必须等待t1线程结束才会执行,因为他们两个线程执行的方法上都有synchronized关键字,即执行前都要获得对象锁;而两个线程共享一个实例对象m,所以谁先拿到对象锁谁先执行,然后另一个线程等着对象锁释放,直到拿到对象锁才会进入运行状态;

例三:

//Main中更改:
		//new了两个myClass对象
		myClass3 m1 = new myClass3();
        myClass3 m2 = new myClass3();
        Thread t1 = new Thread(new myThread3(m1));
        Thread t2 = new Thread(new myThread3(m2));
//把上面的doOther方法加上synchronized关键字
public synchronized void doOther(){
        System.out.println("doOther begin...");
        System.out.println("doOther over...");
    }

结果:
在这里插入图片描述
总结:
t2线程的执行不会等待t1线程结束后执行,虽然两个方法都用到了线程同步,但是这两个线程各自拥有一个myClass对象实例,因此一共会有两把对象锁;每个线程各自有自己的对象锁,所以在执行的过程中互不影响。

例四:

//Main中更改:
		//new了两个myClass对象
		myClass3 m1 = new myClass3();
        myClass3 m2 = new myClass3();
        Thread t1 = new Thread(new myThread3(m1));
        Thread t2 = new Thread(new myThread3(m2));
        
        //myClass更改为
class myClass4{
    public static synchronized void doSome(){
        System.out.println("doSome begin...");
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("doSome over...");
    }
    public static synchronized void doOther(){
        System.out.println("doOther begin...");
        System.out.println("doOther over...");
    }
}

结果:
在这里插入图片描述
总结:
t2线程的执行会等待t1线程的结束后执行,因为在静态方法上添加synchronized关键字之后就相当于加上了类锁,而类锁只有一把,不管new多少了对象也是只有一把,一个线程拿到这个类锁之后,其他线程想要执行public static synchronized修饰的方法就必须等待。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

译制片~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值