Java-并发-一文搞懂线程同步以及同步块和同步函数的概念

什么是线程同步

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

同步的前提

  1. 多个线程执行的时候访问共享数据时需要同步,如果是单线程则不需要同步。
  2. 多个线程在执行的过程中是不是使用同一把锁。如果是,就是同步。否则不是同步。

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修饰变量,保证操作的可见性和原子性并禁止指令重排序。

同步块

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

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

  上面代码的含义为:线程开始执行同步代码块之前,必须先获得对同步监视器的锁定。任何时候只能有一条线程可以获得同步监视器的锁定,并且sleep的线程不会释放同步锁。当同步代码块执行完之后,该线程会释放对该同步监视器的锁定。
  注意多条线程并须使用同一把锁,否则“锁”便没有作用!

同步函数

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

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

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

共同的优缺点:
  优点:线程同步,解决了数据的安全问题。
  缺点:当线程较多时,每一条线程每次运行都会去判断获取同步锁,这是很消耗资源的,会降低运行效率。
同步块优点:

  1. 锁范围自定义。
  2. 锁对象可以是任意对象,除了null,但必须是同一把锁对象。
  3. 如果在线程同步当中需要使用多个锁对象,只能使用同步块。

同步块缺点:

  1. 增加了代码的层级。

同步函数优点:

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

同步函数缺点:

  1. 锁对象是默认的:普通方法锁对象是this锁;静态方法的是字节码文件对象。
  2. 锁的范围是整个方法,不灵活。
发布了29 篇原创文章 · 获赞 47 · 访问量 8196

猜你喜欢

转载自blog.csdn.net/weixin_43767015/article/details/104961199