我是靠谱客的博主 英勇白昼,最近开发中收集的这篇文章主要介绍进程与线程之Synchronized关键字一、并发编程的三大特性二、使用方式三、底层原理四、锁的升级五、volatile关键字,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

一、并发编程的三大特性

1.原子性

2.可见性

3.有序性

二、使用方式

1.同步代码块

2.同步方法

3.修饰静态方法

4.使用规则

5.简单的应用

三、底层原理

1.对象监视器monitor

2.同步代码块

(1)monitor.enter

(3)monitor.exit

3.同步方法

四、锁的升级

1.偏向锁

(1)偏向锁的获取过程

(2)偏向锁的释放

2.轻量级锁

(1)轻量级锁的获取

(2)轻量级锁的释放

3.重量级锁

4.悲观锁

5.乐观锁

6.练习

五、volatile关键字


 


一、并发编程的三大特性

1.原子性

原子操作是不可分割的操作,一个原子操作是不会被其他线程打断的,所以不需要同步

2.可见性

多个线程访问同一共享数据的时候,如果某一个线程修改了此共享数据,那么其他线程能够立即看到此数据的改变。

3.有序性

编译器和处理器为了更好的提升我们所写的代码性能,在执行前会进行指令重排的操作,这一项操作对单线程没有影响,但是会导致多线程出现问题。所以为保证多线程的安全,应该确保操作的有序性。

  • Synchronized关键字保证了并发三大特性中的原子性、有序性、可见性

二、使用方式

  • 修饰代码块,即同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象。
  • 修饰普通方法,即同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。
  • 修饰静态方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象。

1.同步代码块

public final Object obj = new Object();
public void sync(){
    synchornized(obj){
        //需要保证独占性的资源
    }
}

2.同步方法

public synchornized void sync(){
    //表示要访问这个成员方法必须获取当前方法所在类的this引用的锁
}

3.修饰静态方法

public synchronized static void method() {
   // todo
}

4.使用规则

5.简单的应用

class Mythread implements Runnable{
//同步方法
    public synchronized void test1(){
        //获取MyThread类当前this引用的对象锁
        int i=5;
        while(i >= 1){
            System.out.println(Thread.currentThread().getName()+"::"+i--);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void test2(){
//同步代码块
        synchronized (Mythread.class){
            //获取当前Mythread类中class对象的对象锁
            int i=5;
            while(i >= 1){
                System.out.println(Thread.currentThread().getName()+"::"+i--);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void run() {
        test1();
//        test2();
    }
}

三、底层原理

1.对象监视器monitor

 JVM 是通过进入、退出 对象监视器(Monitor) 来实现对方法、同步块的同步的,而对象监视器的本质依赖于底层操作系统的 互斥锁(Mutex Lock) 实现。

在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能,这些标记字段组成了对象头。对象头中包含mark word用来记录对象和锁的相关信息。

在底层原理中涉及到了同步代码块以及同步方法

2.同步代码块

(1)monitor.enter

每一个对象都跟一个monitor相关联,一个monitor的lock在某一个时刻只能够被一个 线程锁获得,在一个线程中想要获取monitor的所有权,接下里有如下几件事情发生:

  • 如果montior的计数器为0,则意味者当前monitor的lock还没有被获得,某个线程 获得之后对该计数器加一,该线程就是这个monitor的所有者了
  • 如果当前这个线程已经获取这把monitor lock,再次获取导致monitor计数器再次+1
  • 如果monitor已经被其他线程所拥有,则当前线程会被陷入阻塞状态直到monitor的计 数器变为,再次去尝试获取对monitor的所有权

(3)monitor.exit

释放对monitor所有权即对monitor的计数器-1,当计数器结果为0,那就意味着当前 线程不再拥有对monitor的使用锁

3.同步方法

class文件中静态常量池ACC_SYNCHRONIZED,表示当前的方法是同步方法

四、锁的升级

1.偏向锁

在大多数情况,锁不仅不存在线程竞争,而且总是会由同一线程多次获得,引入了偏向锁

(1)偏向锁的获取过程

(1)访问Mark Word中偏向锁的标识是否设置成“1”,锁标志位是否为“01”——确认为可偏向状态。
(2)如果为可偏向状态,判断线程ID是否指向当前线程,如果是进入步骤(5),否则进入步骤(3)。
(3)如果线程ID并未指向当前线程,则通过CAS操作竞争锁。如果竞争成功,则将Mark Word中线程ID设置为当前线程ID,然后执行(5);如果竞争失败,执行(4)。

(4)如果CAS获取偏向锁失败,则表示有竞争。当到达全局安全点(safepoint)时获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码。
(5)执行同步代码。

(2)偏向锁的释放

偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程不会主动去释放偏向锁。

2.轻量级锁

轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用产生的性能消耗。

(1)轻量级锁的获取

轻量级锁获取存在两种情况: .
1)关闭偏向锁功能
2)多个线程竞争偏向锁

(2)轻量级锁的释放

(1)通过CAS操作尝试把线程中复制的Displaced Mark Word对象替换当前的Mark Word。
(2)如果替换成功,整个同步过程完成。
(3)如果替换失败,说明有其他线程尝试过获取该锁(此时锁已膨胀),那就要在释放锁的同时,唤醒被挂起的线程。

3.重量级锁

重量级锁是指当有-一个线程获取锁之后,其他所有等待获取的线程就会处于阻塞状态。

4.悲观锁

总是假设最坏的情况,每一次去拿数据都默认别人会修改,所以每次拿数据 都会上锁,这样就会导致有其他人想要拿数据就会阻塞直到获取到这把锁。

synchornized关键字的实现是悲观锁

  • 悲观锁机制存在的问题:

1)多线程竞争下,加锁、解锁都会导致比较多的上下文切换和调度延时,引起性能问题

2)一个线程池有锁会导致其他需要此锁的线程阻塞

3)数据量大时,独占锁回导致效率低下

4)如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级导致,引起性能 问题

5.乐观锁

每次那数据都默认认为别人不会修改,所以不会上锁,在更新的时候判断再次期间 有没有人修改过这个数据。乐观锁适用于多读的场景,这样可以提高吞吐量。

  • 乐观锁的实现方式

CAS操作包含有三个操作数:

需要读写的内存位置(V)

进行比较的预期值(A)

将写入的新值(B)

首先判断V与A的数值是否相同,若相同将B写入V

JAVA对CAS的支持:

在JDK1.5 中新增 java.util.concurrent (J.U.C)就是建立在CAS之上的。相对于对于 synchronized 这种阻塞算法,CAS是非阻塞算法的一种常见实现。所以J.U.C在性能上有了很大的提升。

getAndIncrement 采用了CAS操作,每次从内存中读取数据然后将此数据和 +1 后的结果进行CAS操作,如果成功就返回结果,否则重试直到成功为止。

  • 版本号机制

共享数据中增加一个字段version,表示该数据的版本号,如果当前的数据发生修改,版本号+1.
thread1->shareData + version->alter version 进行判断,如果当前version与之前拿到的version一致才会进行操作

6.练习

value1 没有进行任何线程安全的保护 、value2 使用乐观锁 CAS 、value3 使用悲观锁 synchronized 运行1000个线程,同时对value1,2,3进行自增操作,看下最终的结果

public class TestDemo {
    private static int value1=0;  //线程不安全
    private static AtomicInteger value2=new AtomicInteger(0);//CAS 乐观锁
    private static int value3=0;//synchornized 悲观锁
    private static synchronized void increaseValue3(){
        value3++;
    }

    public static void main(String[] args) {
        for (int i=0;i<1000;i++){
            new Thread(){
                @Override
                public void run() {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    value1++;
                    value2.getAndIncrement();
                    increaseValue3();
                }
            }.start();
        }
        //查看活跃线程数目
        //活跃线程数目大于2 主要原因是idea工具的原因,会有一个monitor线程
        while (Thread.activeCount()>2){
            Thread.yield();
        }
        try {
            TimeUnit.SECONDS.sleep(10);
            System.out.println("线程不安全"+value1);
            System.out.println("乐观锁"+value2);
            System.out.println("悲观锁"+value3);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

五、volatile关键字

  1. 保证可见性 与Java内存模型相关
  2. 保证有序性 volatile关键字修饰变量,修饰的变量会存在一个lock;的前缀,这个前缀 相当于是一个内存屏障 这个内存屏障可以提供:

(1)确保指令重排序时不会将后面的代码排到内存屏障之前

(2)确保指令重排序时不会将前面的代码排到内存屏障之后

(3)确保在执行到内存屏障修饰的指令时前面的代码已经全部执行完成 d.强制地将线程工作内存中的修改刷新到主内存当中 e.如果是写操作,则会导致其他线程工作内存当中的缓存数据失效

注意:volatile关键字不具备保证原子性的语义,只能够禁止指令重排序,保证共享变量修改 立即刷新至主内存

 

最后

以上就是英勇白昼为你收集整理的进程与线程之Synchronized关键字一、并发编程的三大特性二、使用方式三、底层原理四、锁的升级五、volatile关键字的全部内容,希望文章能够帮你解决进程与线程之Synchronized关键字一、并发编程的三大特性二、使用方式三、底层原理四、锁的升级五、volatile关键字所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部