首页>>后端>>java->Java synchronized同步块和同步函数的区别

Java synchronized同步块和同步函数的区别

时间:2023-12-01 本站 点击:0

1 什么是线程同步

线程同步:即当有一个线程在对一块内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,这种线程访问数据的模式就叫做线程同步。

2 同步的前提

多个线程执行的时候访问共享数据时需要同步,如果是单线程则不需要同步。

多个线程在执行的过程中是不是使用同一把锁。如果是,就是同步。否则不是同步。

3 Java实现线程同步的方法

线程同步的方法有很多,这里介绍常用的6种方法。

同步方法

即由synchronized关键字修饰的方法。 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。

同步代码块

即有synchronized关键字修饰的语句块。 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步。

使用特殊域变量(volatile)实现线程同步

volatile关键字为共享变量的访问提供了一种免锁机制,使用volatile修饰域相当于告诉虚拟机该域可能会被其他线程更新,因此每次使用该域就要重新计算,而不是使用寄存器中的值。volatile禁止重排序,但是不会提供任何原子操作,它也不能用来修饰final类型的变量。

因此volatile可以用在对原性操作的共享变量进行数据同步,但是对于非原子性操作无效。

使用JUC提供的各种锁实现线程同步

JUC中的锁相比如synchronized更加灵活。

ReentrantLock; 可重入锁.互斥锁

ReentrantReadWriteLock 可重入锁.读写锁

使用JUC中的阻塞队列实现线程同步

每次只能有一条线程改变队列的数据,保证了队列的安全,底层使用还是使用的lock锁。

使用JUC中的原子变量实现线程同步

java.util.concurrent.atomic包下的是类的小工具包,支持在单个变量上解除锁的线程安全编程。底层使用的是cas无锁机制操作变量+volatile修饰变量,保证操作的可见性和原子性并禁止指令重排序。

3.1 同步块

使用同步块解决数据安全问题:

  synchronized(obj){     //obj叫做同步监视器,也叫同步锁    //操作的共享数据  }

上面代码的含义为:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。任何时候只能有一条线程可以获得同步监视器的锁定,并且sleep的线程不会释放同步锁。当同步代码块执行完之后,该线程会释放对该同步监视器的锁定。

注意多条线程并须使用同一把锁,否则“锁”便没有作用!

3.2 同步函数

使用同步函数(方法)解决数据安全问题:

 Public (static) synchronized void xx(){    //语句一;   // 语句二; }

3.3 同步块和同步函数的优缺点

共同的优缺点:

优点:线程同步,解决了数据的安全问题。

缺点:当线程较多时,每一条线程每次运行都会去判断获取同步锁,这是很消耗资源的,会降低运行效率。

分别的优缺点:

同步块优点:

锁范围自定义。

锁对象可以是任意对象,除了null,但必须是同一把锁对象。

如果在线程同步当中需要使用多个锁对象,只能使用同步块。

同步块缺点:

增加了代码的层级。

同步函数优点:

使用方便,减少了代码的层级。

同步函数缺点:

锁对象是默认的:普通方法锁对象是this锁;静态方法的是字节码文件对象Class。

锁的范围是整个方法,不灵活。

如果有什么不懂或者需要交流,可以留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/java/5479.html