Android多线程:这是一份全面&详细的Synchronized学习指南

前言

  • Java中,有一个常被忽略 但 非常重要的关键字Synchronized
  • 今天,我将详细讲解 Java关键字Synchronized的所有知识,希望你们会喜欢

Carson带你学多线程系列
基础汇总
Android多线程:基础知识汇总
基础使用
Android多线程:继承Thread类使用(含实例教程)
Android多线程:实现Runnable接口使用(含实例教程)
复合使用
Android多线程:AsyncTask使用教程(含实例讲解)
Android多线程:AsyncTask的原理及源码分析
Android多线程:HandlerThread使用教程(含实例讲解)
Android多线程:HandlerThread原理及源码分析
Android多线程:IntentService使用教程(含实例讲解)
Android多线程:IntentService的原理及源码分析
Android多线程:线程池ThreadPool全方位教学
相关使用
Android异步通信:这是一份全面&详细的Handler机制学习攻略
Android多线程:手把手教你全面学习神秘的Synchronized关键字
Android多线程:带你了解神秘的线程变量 ThreadLocal


目录

示意图


1. 定义

Java中的1个关键字


2. 作用

保证同一时刻最多只有1个线程执行 被Synchronized修饰的方法 / 代码

其他线程 必须等待当前线程执行完该方法 / 代码块后才能执行该方法 / 代码块


3. 应用场景

保证线程安全,解决多线程中的并发同步问题(实现的是阻塞型并发),具体场景如下:

  1. 修饰 实例方法 / 代码块时,(同步)保护的是同一个对象方法的调用 & 当前实例对象
  2. 修饰 静态方法 / 代码块时,(同步)保护的是 静态方法的调用 & class 类对象

4. 原理

  1. 依赖 JVM 实现同步
  2. 底层通过一个监视器对象(monitor)完成, wait()notify() 等方法也依赖于 monitor 对象

监视器锁(monitor)的本质 依赖于 底层操作系统的互斥锁(Mutex Lock)实现


5. 具体使用

Synchronized 用于 修饰 代码块、类的实例方法 & 静态方法

5.1 使用规则

示意图

5.2 锁的类型 & 等级

  • 由于Synchronized 会修饰 代码块、类的实例方法 & 静态方法,故分为不同锁的类型
  • 具体如下

示意图

  • 之间的区别

示意图

5.3 使用方式

/**
 * 对象锁
 */
    public class Test{ 
    // 对象锁:形式1(方法锁) 
    public synchronized void Method1(){ 
        System.out.println("我是对象锁也是方法锁"); 
        try{ 
            Thread.sleep(500); 
        } catch (InterruptedException e){ 
            e.printStackTrace(); 
        } 
 
    } 
 
    // 对象锁:形式2(代码块形式) 
    public void Method2(){ 
        synchronized (this){ 
            System.out.println("我是对象锁"); 
            try{ 
                Thread.sleep(500); 
            } catch (InterruptedException e){ 
                e.printStackTrace(); 
            } 
        } 
 
    } 
 }

/**
 * 方法锁(即对象锁中的形式1)
 */
    public synchronized void Method1(){ 
        System.out.println("我是对象锁也是方法锁"); 
        try{ 
            Thread.sleep(500); 
        } catch (InterruptedException e){ 
            e.printStackTrace(); 
        } 
 
    } 

/**
 * 类锁
 */
public class Test{ 
   // 类锁:形式1 :锁静态方法
    public static synchronized void Method1(){ 
        System.out.println("我是类锁一号"); 
        try{ 
            Thread.sleep(500); 
        } catch (InterruptedException e){ 
            e.printStackTrace(); 
        } 
 
    } 
 
    // 类锁:形式2 :锁静态代码块
    public void Method2(){ 
        synchronized (Test.class){ 
            System.out.println("我是类锁二号"); 
            try{ 
                Thread.sleep(500); 
            } catch (InterruptedException e){ 
                e.printStackTrace(); 
            } 
 
        } 
 
    } 
}

5.4 特别注意

Synchronized修饰方法时存在缺陷:若修饰1个大的方法,将会大大影响效率

  • 示例
    若使用Synchronized关键字修饰 线程类的run(),由于run()在线程的整个生命期内一直在运行,因此将导致它对本类任何Synchronized方法的调用都永远不会成功

  • 解决方案
    使用 Synchronized关键字声明代码块

该解决方案灵活性高:可针对任意代码块 & 任意指定上锁的对象

代码如下
  synchronized(syncObject) { 
    // 访问或修改被锁保护的共享状态 
    // 上述方法 必须 获得对象 syncObject(类实例或类)的锁
}

6. 特点

示意图

注:原子性、可见性、有序性的定义

示意图


7. 其他控制并发 / 线程同步方式

7.1 Lock、ReentrantLock

  • 简介

示意图

  • 区别

示意图

7.2 CAS

7.2.1 定义

Compare And Swap,即 比较 并 交换,是一种解决并发操作的乐观锁

synchronized锁住的代码块:同一时刻只能由一个线程访问,属于悲观锁

7.2.2 原理
// CAS的操作参数
内存位置(A)
预期原值(B)
预期新值(C)

// 使用CAS解决并发的原理:
// 1. 首先比较A、B,若相等,则更新A中的值为C、返回True;若不相等,则返回false;
// 2. 通过死循环,以不断尝试尝试更新的方式实现并发

// 伪代码如下
public boolean compareAndSwap(long memoryA, int oldB, int newC){
    if(memoryA.get() == oldB){
        memoryA.set(newC);
        return true;
    }
    return false;
}


7.2.3 优点

资源耗费少:相对于synchronized,省去了挂起线程、恢复线程的开销

但,若迟迟得不到更新,死循环对CPU资源也是一种浪费

7.2.4 具体实现方式
  • 使用CAS有个“先检查后执行”的操作
  • 而这种操作在Java中是典型的不安全的操作,所以 CAS在实际中是C++通过调用CPU指令实现的
  • 具体过程
// 1. CAS在Java中的体现为Unsafe类
// 2. Unsafe类会通过C++直接获取到属性的内存地址
// 3. 接下来CAS由C++的Atomic::cmpxchg系列方法实现
7.2.5 典型应用:AtomicInteger

对 i++ 与 i–,通过compareAndSet & 一个死循环实现

compareAndSet函数内部 = 通过jni操作CAS指令。直到CAS操作成功跳出循环

   private volatile int value; 
    /** 
     * Gets the current value. 
     * 
     * @return the current value 
     */ 
    public final int get() { 
        return value; 
    } 
    /** 
     * Atomically increments by one the current value. 
     * 
     * @return the previous value 
     */ 
    public final int getAndIncrement() { 
        for (;;) { 
            int current = get(); 
            int next = current + 1; 
            if (compareAndSet(current, next)) 
                return current; 
        } 
    } 
 
    /** 
     * Atomically decrements by one the current value. 
     * 
     * @return the previous value 
     */ 
    public final int getAndDecrement() { 
        for (;;) { 
            int current = get(); 
            int next = current - 1; 
            if (compareAndSet(current, next)) 
                return current; 
        } 
    }

8. 总结

  • 本文主要对Java中常被忽略 但 非常重要的关键字Synchronized进行讲解
  • Carson带你学多线程系列

基础汇总
Android多线程:多线程基础知识汇总
基础使用
Android多线程:继承Thread类使用(含实例教程)
Android多线程:实现Runnable接口使用(含实例教程)
复合使用
Android多线程:AsyncTask使用教程(含实例讲解)
Android多线程:AsyncTask的原理及源码分析
Android多线程:HandlerThread使用教程(含实例讲解)
Android多线程:HandlerThread的原理及源码分析
Android多线程:IntentService使用教程(含实例讲解)
Android多线程:IntentService的原理及源码分析
Android多线程:线程池ThreadPool全方位教学
相关使用
Android异步通信:这是一份全面&详细的Handler机制学习攻略
Android多线程:手把手教你全面学习神秘的Synchronized关键字
Android多线程:带你了解神秘的线程变量 ThreadLocal


欢迎关注Carson_Ho的CSDN博客 与 公众号!

博客链接:https://carsonho.blog.csdn.net/


请帮顶 / 评论点赞!因为你的鼓励是我写作的最大动力!

  • 65
    点赞
  • 313
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
Android多线程是指在Android应用程序中同时执行多个线程的技术。在Android开发中,多线程主要用于处理耗时操作,以避免阻塞主线程(也称为UI线程),从而提高应用的响应性能。 在Android中,常用的多线程技术包括以下几种: 1. AsyncTask:这是一种轻量级的异步任务类,适用于较简单的后台任务。它封装了线程的管理和与UI线程的交互,可以在UI线程中执行一些耗时操作,如网络请求、数据库查询等。 2. HandlerThread:这是一种带有消息队列的线程类。它可以用来创建一个后台线程,并通过Handler与UI线程进行通信。通常用于执行需要长时间运行的任务或周期性任务。 3. ThreadPoolExecutor:这是一个线程池类,可以管理多个线程并发执行任务。通过使用线程池,可以有效地重用线程、控制并发数量、管理线程的生命周期等。 4. IntentService:这是一种继承自Service的特殊服务类,用于执行后台任务。它会自动创建工作线程来处理任务,并在任务完成后自动停止。 5. RxJava这是一个响应式编程库,可以简化多线程编程。通过使用观察者模式和链式调用,可以方便地实现异步操作和线程切换。 除了以上几种常用的多线程技术,还可以使用Java原生的Thread类来创建和管理线程,但需要注意在UI线程中的使用,避免阻塞UI的响应。 在使用多线程时,需要注意线程安全性,避免出现数据竞争和死锁等问题。同时,也要合理地管理线程的生命周期,确保在不需要时及时停止和释放资源。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值