synchronized详解

1.synchronized简介:
1.1synchronized的作用:
官方解释:
Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors:if an objects is visible to more than one thread,all reads or writes to thar object’s variable are done through synchronized methods.

翻译:
Synchronized方法支持一种简单的策略,用于防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读或写操作都通过Synchronized方法完成。

总结一句话:能够保证在同一时刻最多只有一个线程执行该段代码,以保证并发安全的效果。

1.2synchronized的地位:
(1)synchronized是Java的关键字,被Java语言原生支持。
(2)是最基本的互斥手段。

1.3不用并发后果代码演示和原因分析
在这里插入图片描述
运行结果:
在这里插入图片描述
原因分析:我们发现结果和我们预期的结果不一样,为什么呢?主要原因是因为i++这个操作包含了三个动作,首先线程要去主内存中读取i的值,然后在自己的工作内存中把i+1,最后再把改变后的值写入主内存。在这个过程中线程有可能被中断,两个线程从主内存中读取的值有可能一样,然后往主内存中写值的过程中,后一个线程有可能会把前一个线程写的值覆盖。

2.synchronized的两个用法(对象锁和类锁):

2.1对象锁:包括方法锁(默认锁对象为this当前实例对象)和同步代码块锁(自己指定锁对象)。

用this对象作为锁:

在这里插入图片描述
结果:
在这里插入图片描述
用两个不同的Object对象作为锁:

public class SynchronizedObjectCodeBlock2 implements Runnable {
    static SynchronizedObjectCodeBlock2 soCodeBlock=new SynchronizedObjectCodeBlock2();
    static Object obj01=new Object();
    static Object obj02=new Object();
    @Override
    public void run() {
        synchronized (obj01) {
            System.out.println("我是lock1。我叫" + Thread.currentThread().getName());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "lock1部分运行结束");
        }

        synchronized (obj02) {
            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 thread01 = new Thread(soCodeBlock);
        Thread thread02 = new Thread(soCodeBlock);
        thread01.start();
        thread02.start();
        while (thread01.isAlive() || thread02.isAlive()){

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

结果:
在这里插入图片描述
用相同的object对象作为锁:

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

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

结果:
在这里插入图片描述
普通方法锁:

public class SynchronizedObjectMethod3 implements Runnable {
    static SynchronizedObjectMethod3 soMethod=new SynchronizedObjectMethod3();
    @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()+"运行结束");
    }
    public static void main(String[] args) {
        Thread thread01 = new Thread(soMethod);
        Thread thread02 = new Thread(soMethod);
        thread01.start();
        thread02.start();
        while (thread01.isAlive() || thread02.isAlive()){

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

结果:
在这里插入图片描述
2.2类锁:指synchronized修饰静态的方法或指定锁为Class对象。

静态方法锁:

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 thread01 = new Thread(instance1);
        Thread thread02 = new Thread(instance2);
        thread01.start();
        thread02.start();
        while (thread01.isAlive() || thread02.isAlive()){

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

结果:
在这里插入图片描述

如果method()方法不加static,那么结果为:

在这里插入图片描述

结论:因为在这个例子中是两个runnable实例,如果访问没有加static修饰的方法,那么它们获得的锁是两把不同的对象锁,所以它们可以同时访问method方法,但是如果访问加static的方法,那么它们获得的锁是同一把锁,是类锁(所谓类锁就是Class对象的锁,java类可以有多个对象,但只有一个Class对象),所以它们不能同时访问。

类锁的第二种形式,synchronized(*.class)

public class SynchronizedClassClass5 implements Runnable{
    static SynchronizedClassClass5 instance1 = new SynchronizedClassClass5();
    static SynchronizedClassClass5 instance2 = new SynchronizedClassClass5();
    @Override
    public void run() {
        method();
    }
    public  void method(){
        synchronized (SynchronizedClassClass5.class) {
            System.out.println("我是类锁的第二种形式:synchronized(*.class)形式,我叫" + 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 thread01 = new Thread(instance1);
        Thread thread02 = new Thread(instance2);
        thread01.start();
        thread02.start();
        while (thread01.isAlive() || thread02.isAlive()){

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

结果:
在这里插入图片描述
3.synchronized关键字的性质:

3.1可重入性
什么是可重入性:指的是同一线程的外层函数获得锁之后,内层函数可以直接获取改锁。

好处:避免死锁、提升封装性。

粒度:线程而非调用。

3.2不可中断行
什么是不可中断性:一旦这个锁被别人获取了,如果我还想获取,我只能选择等待或者阻塞,直到别的线程释放这个锁。如果别人永远不释放锁,那么我只能永远的等下去。

4.synchronized关键字的缺陷:

4.1效率低:锁的释放情况少、试图获取锁时不能设定超时时间、不能中断一个正在试图获取锁的线程。

4.2不够灵活(读写锁更加灵活):加锁和释放锁的时机单一,每个锁仅有单一的条件(每个对象),可能是不够的。

4.3无法知道是否成功获取到锁。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值