Android多线程开发核心知识点

news2024/11/15 21:11:07

什么是线程并发安全

  • 线程安全的本质是能够让并发线程,有序的运行(这个有序可能是先来后到的排队,有可能有人插队,但是不管怎么着,同一时刻只能一个线程有权访问同步资源),线程执行的结果,能够对其他线程可见。

线程安全的几种分类

  • synchronized关键字
  • ReentrantLock锁
  • AtomicInteger…原子类

在这里插入图片描述

  • 锁适合写操作多的场景,先加锁可以保证写操作时数据正确。
  • 原子类适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。

如何保证线程安全

  • AtomicInteger原子包装类,CAS实现无锁数据更新。自旋的设计有效避免线程因阻塞-唤醒带来的系统资源开销。自旋其实就是一个do-while循环。
  • 适用场景:多线程计数,原子操作,并发数量小的场景。

在这里插入图片描述
在这里插入图片描述

  • synchronized
    锁java对象,锁class对象,锁代码块

    • 锁方法。加在方法上,未获取到对象锁的其他线程都不可以访问该方法。
      在这里插入图片描述

    • 锁class对象。加在static方法上相当于给class对象加锁,哪怕是不同的java对象实例,也需要排队执行。
      在这里插入图片描述

    • 锁代码块。未获取到对象锁的其他线程可以执行同步块之外的代码。
      在这里插入图片描述
      在这里插入图片描述

  • ReentrantLock 悲观锁,可重入锁,公平锁,非公平锁

    1. 基本用法
package com.example.myapplication.demo;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {

    static class ReentrantLockTask{
        ReentrantLock reentrantLock = new ReentrantLock();

        void buyTicket(){
            String name= Thread.currentThread().getName();
            try {
                reentrantLock.lock();
                System.out.println(name+":准备好了");
                Thread.sleep(100);
                System.out.println(name+":买好了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantLockTask task = new ReentrantLockTask();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.buyTicket();
            }
        };

        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}

//执行结果:
/*
Thread-2:准备好了
Thread-2:买好了
Thread-3:准备好了
Thread-3:买好了
Thread-4:准备好了
Thread-4:买好了
Thread-5:准备好了
Thread-5:买好了
Thread-6:准备好了
Thread-6:买好了
Thread-7:准备好了
Thread-7:买好了
Thread-8:准备好了
Thread-8:买好了
Thread-9:准备好了
Thread-9:买好了
Thread-10:准备好了
Thread-10:买好了
Thread-11:准备好了
Thread-11:买好了
*/
  1. 可重入,避免死锁
package com.example.myapplication.demo;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {

    static class ReentrantLockTask{
        ReentrantLock reentrantLock = new ReentrantLock();

        void buyTicket(){
            String name= Thread.currentThread().getName();
            try {
                reentrantLock.lock();
                System.out.println(name+":准备好了");
                Thread.sleep(100);
                System.out.println(name+":买好了");
                reentrantLock.lock();
                System.out.println(name+":又准备好了");
                Thread.sleep(100);
                System.out.println(name+":又买好了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
                reentrantLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantLockTask task = new ReentrantLockTask();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.buyTicket();
            }
        };

        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}
/*
Thread-2:准备好了
Thread-2:买好了
Thread-2:又准备好了
Thread-2:又买好了
Thread-3:准备好了
Thread-3:买好了
Thread-3:又准备好了
Thread-3:又买好了
Thread-4:准备好了
Thread-4:买好了
Thread-4:又准备好了
Thread-4:又买好了
Thread-5:准备好了
Thread-5:买好了
Thread-5:又准备好了
Thread-5:又买好了
Thread-6:准备好了
Thread-6:买好了
Thread-6:又准备好了
Thread-6:又买好了
Thread-7:准备好了
Thread-7:买好了
Thread-7:又准备好了
Thread-7:又买好了
Thread-8:准备好了
Thread-8:买好了
Thread-8:又准备好了
Thread-8:又买好了
Thread-9:准备好了
Thread-9:买好了
Thread-9:又准备好了
Thread-9:又买好了
Thread-10:准备好了
Thread-10:买好了
Thread-10:又准备好了
Thread-10:又买好了
Thread-11:准备好了
Thread-11:买好了
Thread-11:又准备好了
Thread-11:又买好了

*/
  1. 公平锁与非公平锁

    • 公平锁,所有进入阻塞的线程排队依次均有机会执行。使用场景:交易
    • 默认非公平锁,允许线程插队,避免每一个线程都进入阻塞,再唤醒,性能高。因为线程可以插队,导致队列中可能会存在线程饿死的情况,一直得不到锁,一直得不到执行。
ReentrantLock reentrantLock = new ReentrantLock(true/false);//true:公平;false不公平
package com.example.myapplication.demo.lock;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo2 {
    static class ReentrantLockTask{
        ReentrantLock lock = new ReentrantLock(false);

        void print(){
            String name = Thread.currentThread().getName();
            try {
                lock.lock();
                System.out.println(name+"第一次打印");
                Thread.sleep(1000);
                lock.unlock();

                lock.lock();
                System.out.println(name+"第二次打印");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantLockTask task = new ReentrantLockTask();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.print();
            }
        };

        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}
/*
  Thread-2第一次打印
Thread-2第二次打印
Thread-3第一次打印
Thread-3第二次打印
Thread-4第一次打印
Thread-4第二次打印
Thread-5第一次打印
Thread-5第二次打印
Thread-6第一次打印
Thread-6第二次打印
Thread-7第一次打印
Thread-7第二次打印
Thread-8第一次打印
Thread-8第二次打印
Thread-9第一次打印
Thread-9第二次打印
Thread-10第一次打印
Thread-10第二次打印
Thread-11第一次打印
Thread-11第二次打印
*/
package com.example.myapplication.demo.lock;

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo2 {
    static class ReentrantLockTask{
        ReentrantLock lock = new ReentrantLock(true);

        void print(){
            String name = Thread.currentThread().getName();
            try {
                lock.lock();
                System.out.println(name+"第一次打印");
                Thread.sleep(1000);
                lock.unlock();

                lock.lock();
                System.out.println(name+"第二次打印");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantLockTask task = new ReentrantLockTask();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                task.print();
            }
        };

        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}
/*
Thread-2第一次打印
Thread-3第一次打印
Thread-4第一次打印
Thread-5第一次打印
Thread-6第一次打印
Thread-7第一次打印
Thread-8第一次打印
Thread-9第一次打印
Thread-10第一次打印
Thread-11第一次打印
Thread-2第二次打印
Thread-3第二次打印
Thread-4第二次打印
Thread-5第二次打印
Thread-6第二次打印
Thread-7第二次打印
Thread-8第二次打印
Thread-9第二次打印
Thread-10第二次打印
Thread-11第二次打印
*/
  1. ReentrantLock进阶用法 ——Condition条件对象
    可以使用它的await-singnal指定唤醒一个(组)线程。相比于wait-notify要么全部唤醒,要么只能唤醒一个,更加灵活可控。
package com.example.myapplication.demo.lock;

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo3 {
    static class ReentrantLockTask {

        private Condition workerCondition, worker2Condition;
        ReentrantLock lock = new ReentrantLock(true);

        volatile int flag = 0;

        public ReentrantLockTask() {
            workerCondition = lock.newCondition();
            worker2Condition = lock.newCondition();
        }

        void work1() {
            try {
                lock.lock();
                if (flag == 0 || flag % 2 == 0) {
                    System.out.println("worker1 休息会");
                    workerCondition.await();
                }
                System.out.println("worker1 搬到的砖是:" + flag);
                flag = 0;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        void work2() {
            try {
                lock.lock();
                if (flag == 0 || flag % 2 != 0) {
                    System.out.println("worker2 休息会");
                    worker2Condition.await();
                }
                System.out.println("worker2 搬到的砖是:" + flag);
                flag = 0;
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        void boss() {
            try {
                lock.lock();
                flag = new Random().nextInt(100);
                if (flag % 2 == 0) {
                    worker2Condition.signal();
                    System.out.println("唤醒工人2:"+flag);
                }else {
                    workerCondition.signal();
                    System.out.println("唤醒工人1:"+flag);
                }
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantLockTask lockTask = new ReentrantLockTask();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                   lockTask.work1();
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    lockTask.work2();
                }
            }
        }).start();

        for (int i = 0; i < 10; i++) {
            lockTask.boss();
        }
    }
}
/*

worker1 休息会
唤醒工人2:82
worker2 搬到的砖是:82
唤醒工人1:17
worker2 休息会
worker1 搬到的砖是:17
唤醒工人1:71
worker1 搬到的砖是:71
唤醒工人1:59
worker1 搬到的砖是:59
唤醒工人1:77
worker1 搬到的砖是:77
唤醒工人1:87
worker1 搬到的砖是:87
唤醒工人2:54
worker1 休息会
worker2 搬到的砖是:54
唤醒工人2:80
worker2 搬到的砖是:80
唤醒工人2:42
worker2 搬到的砖是:42
唤醒工人2:56
worker2 搬到的砖是:56
worker2 休息会
*/
  1. ReentrantReadWriteLock 共享锁、排他锁

    • 共享锁,所有线程均可同时获得,并发量高,比如在线文档查看
    • 排他锁,同一时刻只有一个线程有权修改资源,比如在线文档编辑
package com.example.myapplication.demo.lock;

import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReentrantLockDemo4 {

    static class ReentrantReadWriteLockTask{
        private final ReentrantReadWriteLock.ReadLock readLock;
        private final ReentrantReadWriteLock.WriteLock writeLock;
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

        ReentrantReadWriteLockTask(){
            readLock  = lock.readLock();
            writeLock = lock.writeLock();
        }

        void read(){
            String name = Thread.currentThread().getName();
            try {
                readLock.lock();
                System.out.println("线程"+name+" 正在获取数据...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                readLock.unlock();
                System.out.println("线程"+name+" 释放了读锁...");
            }
        }

        void write(){
            String name = Thread.currentThread().getName();
            try {
                writeLock.lock();
                System.out.println("线程"+name+" 正在写入数据...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                writeLock.unlock();
                System.out.println("线程"+name+" 释放了写锁...");
            }
        }
    }

    public static void main(String[] args) {
        final ReentrantReadWriteLockTask task = new ReentrantReadWriteLockTask();

        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    task.read();//因为是读写锁,所以3个线程的日志会一起打印出来
                }
            }).start();
        }

        for (int i = 0; i < 3; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    task.write();
                }
            }).start();
        }
    }
}
/*
线程Thread-2 正在获取数据...
线程Thread-3 正在获取数据...
线程Thread-4 正在获取数据...
线程Thread-3 释放了读锁...
线程Thread-6 正在写入数据...
线程Thread-2 释放了读锁...
线程Thread-4 释放了读锁...
线程Thread-6 释放了写锁...
线程Thread-5 正在写入数据...
线程Thread-5 释放了写锁...
线程Thread-7 正在写入数据...
线程Thread-7 释放了写锁...
*/

如何正确的使用锁&原子类

  • 减少持锁时间
    在这里插入图片描述

  • 锁分离
    在这里插入图片描述

  • 锁粗化
    多次加锁,释放锁合并成一次
    在这里插入图片描述
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言实例_数据压缩与解压

一、压缩与解压介绍 数据压缩是通过一系列的算法和技术将原始数据转换为更紧凑的表示形式&#xff0c;以减少数据占用的存储空间。数据解压缩则是将压缩后的数据恢复到原始的表示形式。 数据可以被压缩打包并减少空间占用的原因有以下几个方面&#xff1a; &#xff08;1&am…

Python支持下Noah-MP陆面模式站点、区域模拟及可视化分析

熟悉陆表过程的主要研究内容以及陆面模型在生态水文研究中的地位和作用&#xff1b;深入理解Noah-MP 5.0模型的原理&#xff0c;掌握Noah-MP模型&#xff08;2023年最新发布的5.0版本&#xff09;所需的系统环境与编译环境的搭建方法及模型实践运行&#xff0c;熟悉linux系统操…

高忆管理大盘行情:美股开盘时间?

股票商场是一个充满生机的环境&#xff0c;而美股作为全球最具生机和最具影响力的股票商场之一&#xff0c;被投资者和买卖员广泛关注。美股开盘时刻是众多投资者和买卖员最为关心的问题之一&#xff0c;由于不同的买卖时刻会对在商场中进行投资产生重要影响。那么&#xff0c;…

虹科分享 | 如何构建深度防御层 | 自动移动目标防御

在当今的威胁环境中&#xff0c;多层纵深防御是安全团队获得安心的唯一方法之一。 为什么?有两个原因: 1、攻击面越来越大 随着DevOps等远程工作和数字化转型项目的兴起&#xff0c;攻击面已经超出了大多数安全团队的定义能力。创建一个完全安全的网络边界是不可能的。正如…

计算机视觉-图形处理基础

一、环境安装 1、anaconda安装 官网下载&#xff1a;Free Download | Anaconda 2、打开anaconda prompt测试是否安装成功 输入conda env list命令显示虚拟环境清单即可 二、创建开发虚拟环境 1、创建python3.8虚拟环境 conda create --name demo_py3.8 python3.8 2、激…

ubuntu18 编译ROS代码 报“cxx_attribute_deprecated”is not know to CXX compiler

编译代码报错如下&#xff1a; 通常用两种解决方式&#xff1a; 1&#xff1a;先检查一下 编写的CMakeList.txt的文件中&#xff0c;所包含、链接的文件和库是否都存在且引用正确&#xff08;仔细的查看了一下&#xff0c;都是正确的&#xff09; 2&#xff1a;查看一下cmake…

iOS 17 及 Xcode 15.0 Beta7 问题记录

1、iOS 17 真机调试问题 iOS 17之后&#xff0c;真机调试Beta版本必须使用Beta版本的Xcode来调试&#xff0c;用以前复制DeviceSupport 方式无法调试&#xff0c;新的Beta版本Xcode中&#xff0c;已经不包含 iOS 17目录。如下图&#xff1a; 解决方案&#xff1a; 1&#x…

数据驱动的胜利:体育赛事的可视化之道

当前&#xff0c;体育赛事遍地开花&#xff0c;智能体育也不断成熟。体育赛事不断与物联网、数字孪生等新一代信息技术深入融合&#xff0c;创新运动方式&#xff0c;推动全民健身&#xff0c;促进产业升级。数字孪生可视化平台易知微也一直致力于体育领域的数字化发展&#xf…

Elexcon2023深圳国际电子展开幕,飞凌嵌入式重装亮相!

8月23日&#xff0c;Elexcon2023深圳国际电子展正式开幕&#xff0c;近600家全球优质品牌厂商齐聚深圳会展中心&#xff08;福田&#xff09;&#xff0c;并有上万名观众来到现场参观、交流。飞凌嵌入式携多款多类型的智能主控产品及热门行业解决方案亮相盛会&#xff0c;展位号…

基于 SpringBoot+Vue+Java 的财务管理系统,附源码,教程

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 一 简介第二.主要技术第三、部分效果图第四章 系统设计4.1功能结构4.2 数据库设计4.2.1 数据库E/R…

如何使用图形数据库构建实时推荐引擎

推荐&#xff1a;使用 NSDT场景编辑器助你快速搭建可二次编辑的3D应用场景 “这是给你的”&#xff0c;“为你推荐的”或“你可能也喜欢”&#xff0c;是大多数数字业务中必不可少的短语&#xff0c;特别是在电子商务或流媒体平台中。 尽管它们看起来像一个简单的概念&#xf…

Linux 设置mysql开机自启动和安装JDK

0目录 1.mysql设置开机自启动 2.linux安装jdk 1.mysql设置开机自启动 去到cd /etc/rc.d/init.d目录 创建一个sh脚本 编辑脚本 设置开机自启动 重启 检查是否自启动 2.linux安装jdk 下载安装包 放在opt目录下 新建soft文件夹&#xff08;opt目录下&#xff09;…

window版本的kibana的安装,使用,启动

前言&#xff1a;本篇是根据小破站UP主遇见狂神说学习篇&#xff0c; 这里是我做的笔记&#xff0c;&#xff08;ElasticSearch7.6入门学习笔记-KuangStudy-文章&#xff09;&#xff0c;up主的文档肯定比我更清晰&#xff0c;但我还是记录一下嘿嘿嘿&#xff0c;下面直接开始 …

用户管理与用户权限

数据库用户管理 新建用户 CREATE USER 用户名来源地址 [IDENTIFIED BY [PASSWORD] 密码]; 用户名&#xff1a;指定将创建的用户名. 来源地址&#xff1a;指定新创建的用户可在哪些主机上登录&#xff0c;可使用IP地址、网段、主机名的形式&#xff0c;本地用户可用localhost&…

【全站最全】被苹果、谷歌和Microsoft停产的产品(三)

2016 Narrative Clip 2012 – 2016 HARDWARE Narrative Clip was small wearable capable of automatically take a picture every 30 seconds whilst being worn throughout the day, a practice known as "life-logging". Pebble 2013 – 2016 HARDWARE Pe…

C#+WPF上位机开发(模块化+反应式)作者:重庆教主

在上位机开发领域中&#xff0c;C#与C两种语言是应用最多的两种开发语言&#xff0c;在C语言中&#xff0c;与之搭配的前端框架通常以QT最为常用&#xff0c;而C#语言中&#xff0c;与之搭配的前端框架是Winform和WPF两种框架。今天我们主要讨论一下C#和WPF这一对组合在上位机开…

SUI 将通过 SUI Foundation 资助 Footprint Analytics 解析其公链数据,为生态系统提供支持

2023 年 8 月 23 日消息&#xff0c;SUI 基金会宣布将赞助链上数据提供商 Footprint Analytics&#xff0c;旨在协助解析公链数据&#xff0c;为 SUI 的生态系统及其开发者提供全方位支持。 Footprint Analytics 将提供完整的数据报表和 API 接口&#xff0c; SUI 链的用户可以…

uniapp离线打包apk - Android Studio

uniapp 离线打包 基于uni-app的andiord 离线打包 开发工具及所需要的jar包​1.将下载的App离线SDK解压打开&#xff0c;找到HBuilder-Integrate-AS &#xff0c;在Android Studio打开2.打开HBuilder X&#xff0c;发行->原生app本地打包->生成本地打包app资源3.在“HBuil…

GitLab-CI 指南

GitLab CI 指南 前置工作 部署GitLab 部署GitLab-Runner 注册Runner到GitLab docker exec -it gitlab-runner bash # 进入容器 gitlab-runner register #调用register命令开始注册 # 在Gitlab Setting中找到Runners,如下图所示Enter the GitLab instance URL (for example, …

做不做软测都能学的技能,一招化解磁盘空间不足!

如&#xff0c;我有一台服务器&#xff0c;磁盘空间为 50g 现在&#xff0c;使用了一段时间之后&#xff0c;磁盘空间不够了 磁盘空间不够&#xff0c;这个时候&#xff0c;如果你再执行某些写入磁盘的操作就会报错&#xff0c;无法执行。 测试服务器磁盘空间不够&#xff0c;…