Android多线程之同步锁的使用

2023-10-26

本文主要介绍了Android多线程之同步锁的使用,分享给大家,具体如下:

一、同步机制关键字synchronized

对于Java来说,最常用的同步机制就是synchronized关键字,他是一种基于语言的粗略锁,能够作用于对象、函数、class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的这个Class类,并非具体对象。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class SynchronizedClass {

  public synchronized void syncMethod(){

    //代码

  }

 

  public void syncThis(){

    synchronized (this){

      //代码

    }

  }

 

  public void syncClassMethod(){

    synchronized (SynchronizedClass.class){

      //代码

    }

  }

 

  public synchronized static void syncStaticMethod(){

    //代码

  }

}

上面演示了同步方法、同步块、同步class对象、同步静态方法。前2种锁的是对象,而后两种锁的是class对象。对于class对象来说,它的作用是防止多个线程同时访问添加了synchronized锁的代码块,而synchronized作用于引用对象是防止其他线程访问同一个对象中synchronized代码块或者函数。

二、显示锁———-ReentrankLock和Condition

ReentrankLock 和内置锁synchronized相比,实现了相同的语义,但是更具有更高的灵活性。

(1)获得和释放的灵活性。
(2)轮训锁和定时锁。
(3)公平性。

基本操作:

lock(): 获取锁

tryLock(): 尝试获取锁

tryLock(long timeout,TimeUnit unit): 尝试获取锁,如果到了指定的时间还获取不到,那么超时。

unlock(): 释放锁

newCondition(): 获取锁的 Condition

使用ReentrantLock的一般组合是 lock、tryLock、与unLock成对出现,需要注意的是,千万不要忘记调用unlock来释放锁,负责可能引发死锁的问题。ReentrantLock的常用形式如下所示:

?

1

2

3

4

5

6

7

8

9

10

11

12

public class ReentrantLockDemo {

  Lock lock = new ReentrantLock();

 

  public void doSth(){

    lock.lock();

    try {

      //执行某些操作

    }finally {

      lock.unlock();

    }

  }

}

需要注意的是,lock必须在finally开中释放,否则,如果受保护的代码抛出异常,锁就可能永远得不到释放!!

ReentrantLock类中还有一个重要的函数newCondition(),该函数用户获取Lock()上的一个条件,也就是说Condition与Lock绑定。Condition用于实现线程间的通信,他是为了解决Object.wait(),nofity(),nofityAll() 难以使用的问题。
Condition的方法如下:

await() : 线程等待

await(int time,TimeUnit unit) 线程等待特定的时间,超过的时间则为超时。

signal() 随机唤醒某个等待线程

signal() 唤醒所有等待中的线程

示例代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

public class MyArrayBlockingQueue<T> {

 

//  数据数组

  private final T[] items;

 

  private final Lock lock = new ReentrantLock();

 

  private Condition notFull = lock.newCondition();

  private Condition notEmpty = lock.newCondition() ;

 

//  头部索引

  private int head;

//  尾部索引

  private int tail ;

//  数据的个数

  private int count;

 

  public MyArrayBlockingQueue(int maxSize) {

    items = (T[]) new Object[maxSize];

  }

 

  public MyArrayBlockingQueue(){

    this(10);

  }

 

  public void put(T t){

    lock.lock();

    try {

      while(count == getCapacity()){

        System.out.println("数据已满,等待");

        notFull.await();

      }

      items[tail] =t ;

      if(++tail ==getCapacity()){

        tail = 0;

      }

      ++count;

      notEmpty.signalAll();//唤醒等待数据的线程

    } catch (InterruptedException e) {

      e.printStackTrace();

    }finally {

      lock.unlock();

    }

  }

 

  public int getCapacity(){

    return items.length ;

  }

 

  public T take(){

    lock.lock();

    try {

      while(count ==0){

        System.out.println("还没有数据,等待");

        //哪个线程调用await()则阻塞哪个线程

        notEmpty.await();

      }

      T ret = items[head];

      items[head] = null ;

      if(++head == getCapacity()){

        head =0 ;

      }

      --count;

      notFull.signalAll();

      return ret ;

    } catch (InterruptedException e) {

      e.printStackTrace();

    }finally {

      lock.unlock();

    }

    return null ;

  }

 

  public int size(){

    lock.lock();

    try {

      return count;

    }finally {

      lock.unlock();

    }

  }

 

  public static void main(String[] args){

    MyArrayBlockingQueue<Integer> aQueue = new MyArrayBlockingQueue<>();

    aQueue.put(3);

    aQueue.put(24);

    for(int i=0;i<5;i++){

      System.out.println(aQueue.take());

    }

 

    System.out.println("结束");

  }

}

执行结果:

3
24
还没有数据,等待

三、信号量 Semaphore

Semaphore是一个计数信号量,它的本质是一个“共享锁”。信号量维护了一个信号量许可集,线程可以通过调用acquire()来获取信号量的许可。当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到可用的许可为止。线程可以通过release()来释放它所持有的信号量许可。

示例:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public class SemaphoreTest {

  public static void main(String[] args){

    final ExecutorService executorService = Executors.newFixedThreadPool(3);

    final Semaphore semaphore = new Semaphore(3);

    List<Future> futures = new ArrayList<>();

    for (int i = 0; i < 5; i++) {

      Future<?> submit = executorService.submit(new Runnable() {

        @Override

        public void run() {

          try {

            semaphore.acquire();

            System.out.println(" 剩余许可: " + semaphore.availablePermits());

            Thread.sleep(3000);

            semaphore.release();

          } catch (InterruptedException e) {

            e.printStackTrace();

          }

        }

      });

      futures.add(submit);

    }

  }

}

以上就是本文的全部内容,希望对大家的学习有所帮助

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android多线程之同步锁的使用 的相关文章

随机推荐

  • 在R语言中使用stress.labels参数为可视化图像中的强调线添加标签信息

    在R语言中使用stress labels参数为可视化图像中的强调线添加标签信息 在数据可视化中 我们经常需要突出显示某些线条或数据点 以便更清楚地传达信息 在R语言中 我们可以使用stress labels参数来为图像中的强调线添加标签信息
  • 14.学习Camera之——camera基本知识

    一 Camera模组 大家都知道 手机背面的那个小小的孔 就叫摄像头 这个小孔幽幽的泛着光泽 深邃又迷人 如同 一个含苞待放的小萝莉一样 这个小萝莉还是个傲娇娘 像零之使魔的614一样惹人怜爱 而且在小萝莉身体 里面 不对 是在小孔的里面
  • 大数据组件-Kafka的javaAPI操作,Kafka StreamingAPI开发,

    1 KafkaJavaApi操作 1 添加maven依赖
  • python写客户端发送请求失败_零基础写python爬虫之HTTP异常处理

    先来说一说HTTP的异常处理问题 当urlopen不能够处理一个response时 产生urlError 不过通常的Python APIs异常如ValueError TypeError等也会同时产生 HTTPError是urlError的子
  • iOS单例

    iOS开发中单例模式必不可少 是不是还在写单例的时候还写那一坨代码呢 这里提供一个宏 只需要简单的两句话就可以实现单例无论MRC还是ARC 使用方法 h中 import
  • @Control详解--Spring2.5

    一个简单的基于注解的 Controller 使用过低版本 Spring MVC 的读者都知道 当创建一个 Controller 时 我们需要直接或间接地实现 org springframework web servlet mvc Contr
  • LintCode统计数字:计算数字k在0到n中的出现的次数,k可能是0~9的一个值

    现在是2018 9 21 距离毕业还有不到两年的时间 情况乐观的话 我应该会在一年之内去找一份实习工作 对于找工作这件事 此刻的我还是有些惶恐 我无法确定清晰的职业方向和目标 对自己的知识储备也不自信 为了给即将面对的求职做些准备 我觉得有
  • CSDN证书记录(仅仅只是个人CSDN纪录)

    按照时间线来记录点点滴滴 1 2022年4月 安卓领域实力新星 2 2022年7月 笔耕不辍 3 2022年8月 博客专家
  • 今天百度索引量算是闹了个乌龙吗

    今天百度索引量算是闹了个乌龙吗 各大网站 不论大小 基本上都是索引量砍半 百度站长论坛更是热闹非凡 各种声音都有 百度服务器故障 百度算法大调整 网站被降权了等等 作为老站长的我发现索引量大幅下降后 立马看了百度站长平台中的其他站点 发现都
  • Xilinx FPGA 7系列 GTX/GTH Transceivers (1)

    初识Xlilix GTX 1概述 Xilinx 7系列FPGA全系所支持的GT GT资源是Xilinx系列FPGA的重要卖点 也是做高速接口的基础 GT的意思是Gigabyte Transceiver G比特收发器 不管是PCIE SATA
  • 数据的储存

    数据的存储在C语言中无疑是一个难点 但是也要充满信心征服他的信心 翻过这座山 会看到更广阔的天空 基本数据类型 整型家族 浮点数家族 自定义类型 指针类型 空类型 大小端字节序介绍和判断 整形在内存中的存储 浮点型在内存中的存储 练习 基本
  • uva 11292

    水题 include
  • 2022年秋招求职#end——华为单板硬件

    九月初就在官网创建了简历 但是当时并没有投简历 记录中却是已经投递简历了 害我以为一直都是石沉大海的状态 十月底江哥问我华子怎么样 有没有消息 我才上去官网看 然后重新投递 第一个志愿是逻辑 就是江哥的部门 第二个志愿是老本行电源 然后十月
  • git --login-i_使用Git- Part -I:基础知识

    git login i 介绍 Git是由Linux OS的创建者Linus Torvalds创建的流行的分布式版本控制系统 因此 您可能已经猜到它首先用于版本控制Linux内核代码 它广泛用于大多数开放源代码和封闭源代码软件的开发中 得益于
  • 第四课,视图的显示选项和光照部分

    主要讲了视图的两部分 一个是光照等 一个是说了显示部分 外界的宏观部分
  • css实现渐变色

    日常中最常用到的渐变色是背景和边框 一条线的渐变色可以考虑使用div 然后根据需求设置高度 两种 首先来了解一下绘制渐变色的角度与方向 第一种 背景 使用到的属性为background 接下来看三个关于背景渐变最常用到的实例 有详细注释 方
  • Azure Key Vault(2):创建Azure Key Vault

    如果想要了解Key Vault是干什么的 可以看我的上一篇博文 这里我会说一下如何来创建Key Vault并使用它来保存一个D365连接字符串 如下 AuthType ClientSecret url https contoso 8080
  • 什么是泛型?

    目录 一 什么是泛型 二 泛型方法 三 泛型接口 四 通配符 4 1 通配符 4 2 上限通配符 4 3 下限通配符 4 4 类型擦除 一 什么是泛型 泛型 就是指在类定义时不会设置类中的属性或方法参数的具体类型 而是在类使用时 创建对象
  • request,response中文乱码问题

    request response中文乱码问题 request乱码 浏览器向服务器发送的请求参数中包含中文字符 服务器获取的请求参数的值是乱码 response乱码 服务器向浏览器发送的数据包含中文字符 浏览器中显示的是乱码 产生乱码的原因
  • Android多线程之同步锁的使用

    本文主要介绍了Android多线程之同步锁的使用 分享给大家 具体如下 一 同步机制关键字synchronized 对于Java来说 最常用的同步机制就是synchronized关键字 他是一种基于语言的粗略锁 能够作用于对象 函数 cla