`
clearity
  • 浏览: 36913 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

获得更好并发和线程安全性的场景和解决方案--第三部分 信号量和互斥锁

阅读更多

场景1:web服务通过http请求数据,将请求对象放在内部的队列中,并且有一个单独的工作线程从队列中取请求对象进行处理.比如,一个交易系统创建一个购买订单并放入队列中,这时一个独立的消费线程获取订单信息并且将发送给证券交易所,这是一个典型的生产者消费者场景.

 

场景2:如果之前的条件未知信号量可以用来创建工作线程,这是因为信号量可以在0许可的情况下创建,并在一系列的释放以后运行.比如,如果你想递归的遍历内部文件夹并利用生成的若干线程将html类型的文件转移到目标文件夹中,然后可以通过调用release方法调用递增许可数量, 单独的处理线程需要在开始处理这些文件之前获取足够的许可才可以进行处理.

 

场景3:当需要对共享资源进行递增或者递减的引用计数时,递增、递减或者测试的操作必须是线程安全的。比如,一个用来在用户登录时递增或者在用户登出时递减当前活动用户的计数器.

 

方案:通常情况下,信号量是根据字母顺序代码的某个位置通过持有判断标识来发送消息的实现。在程序设计中,特别是在Unix系统中,信号量是在多个进程竞争相同操作系统资源的时候用来协作或者同步活动的技术。信号量通畅被用于两个目的:共享内存空间和共享文件访问。在java中,信号量是用来对多线程进行协作。

 

Q:互斥锁和信号量之间的区别是什么?

A:互斥锁:好比厕所的钥匙一样。同一时间只能有一个人拥有并且独占厕所。当一个人使用过后,持有钥匙的人会将钥匙传递给队列中的下一个人。在java中,每一个对象都有一个互斥锁并且只能有一个线程可以持有它。

 

   信号量:是一串厕所的钥匙。比如,厕所有三把锁,对应的钥匙有三个。在刚开始时,信号量的值被设置为3,随后当有人拿到钥匙进入厕所后值会递减。如果厕所满了,也就是没有钥匙省下的时候,信号量的值是0.现在,如果有一个人使用完厕所离开后,信号量会递增为1(获得了一个钥匙),并且将钥匙传递给了排队的下个人。

 

这里有使用互斥锁来实现生产者和消费者的例子.

 

public class ProducerConsumer {
 
 private int count;  //被多个线程共享访问的资源
 
 public synchronized void consume() {
  while (count == 0) {
   try {
    wait();    //等待唤醒
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
 
  //如果信号量的值大于0 ,自减
  count--;     //递减1
  System.out.println("Consumed:" + count);
  notify();  //唤醒等待线程恢复运行
 
 }
 
 public synchronized void produce() {
  while(count > 0) {
   try {
    wait();    //wait till notified
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
   
  //如果信号量的值等于0,递增
  count++;
  System.out.println("Produced: " + count);
  notify();   //唤醒等待线程恢复运行
 }
 
 public static void main(String[] args)  {
        //内部类只能访问final类型的变量
  final ProducerConsumer pc = new ProducerConsumer();
 
  //使用匿名内部类创建生成线程
  Runnable producer = new Runnable() {
   @Override
   public void run() {
    for (int i = 0; i < 3; i++) {
     pc.produce(); 
    }
   }
  };
 
   
  //匿名内部类创建消费线程
  Runnable consumer = new Runnable() {
   @Override
   public void run() {
    for (int i = 0; i < 3; i++) {
      pc.consume();
    }
   }
  };
 
  Thread producerThread = new Thread(producer); //主线程中创建新线程
  Thread consumerThread = new Thread(consumer); //主线程中创建新县城
 
  producerThread.start();  // 执行生产线程
  consumerThread.start();  // 执行消费线程
 
 }
}

 

 

现在,让我们来看下Java 5中的信号量的例子。你可以使用一个数量的许可创建信号量,并且可以获得和释放许可。

 

import java.util.concurrent.Semaphore;
 
public class ProducerConsumer2 {
 
 private int count;
  
 /**
  *  调用release方法递增许可
  *  调用acquire方法递减许可
  */
 static Semaphore semCon = new Semaphore(0);
 static Semaphore semProd = new Semaphore(1); //从一个许可开始
 
 public  void consume() {
  try {
   //继续执行前从信号量获取许可
   semCon.acquire();
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 
  count--;
  System.out.println("Consumed:" + count);
  //释放许可,返回给信号量
  semProd.release(); 
 
 }
 
 public void produce() {
  try {
   //执行前获得信号量许可
   semProd.acquire(); 
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  count++;
  System.out.println("Produced: " + count);
  //释放许可,归还给信号量
  semCon.release();   
 }
 
 public static void main(String[] args)  {
 
  final ProducerConsumer2 pc = new ProducerConsumer2();
 
  //匿名内部类生产线程
  Runnable producer = new Runnable() {
   @Override
   public void run() {
    for (int i = 0; i < 3; i++) {
     pc.produce(); 
    }
   }
  };
 
  //匿名内部类消费线程
  Runnable consumer = new Runnable() {
   @Override
   public void run() {
    for (int i = 0; i < 3; i++) {
      pc.consume();
    }
   }
  };
 
  Thread producerThread = new Thread(producer); //主线程创建新线程
  Thread consumerThread = new Thread(consumer); //主线程创建新县城
 
  producerThread.start(); // 启动生产者线程
  consumerThread.start(); // 启动消费者线程
 
 }
}

 

 

上面两端代码的输出:

 

Produced: 1
Consumed:0
Produced: 1
Consumed:0
Produced: 1
Consumed:0

 

分享到:
评论

相关推荐

    Linux互斥锁、条件变量和信号量

    在多线程编程中,确保线程安全是至关重要的,特别是在Linux系统中,为了管理共享资源,Linux提供了互斥锁、条件变量和信号量这三种同步机制。它们都是用于协调多个线程对共享数据的访问,防止数据不一致性和竞态条件...

    信号量、互斥体和自旋锁的区别

    **信号量**、**互斥体**和**自旋锁**是操作系统中三种常用的同步机制,主要用于解决多线程或多进程环境中资源的并发访问问题。这三种机制虽然都用于实现同步控制,但在具体的应用场景和技术特性上存在显著差异。 ##...

    信号量与互斥锁示例代码

    信号量和互斥锁是操作系统中用于进程同步和资源管理的重要机制,它们在多线程编程和并发控制中发挥着至关重要的作用。本示例代码来源于《深入理解计算机系统》这本书,通过具体代码来帮助读者深入理解这两种机制的...

    多线程并发编程-同步与互斥-原⼦变量-并发和⽆锁 数据结构

    信号灯、互斥量、自旋锁和条件变量等都是实现线程同步和互斥的机制。线程同步和互斥的机制可以通过原子变量来实现。 5.3 线程同步和互斥 线程同步和互斥是多线程编程的核心技术之一。信号灯、互斥量、自旋锁和条件...

    C语言并发控制:信号量与互斥锁的实现与应用

    #### 三、使用POSIX线程库实现信号量和互斥锁 在C语言中,可以通过POSIX线程库(pthread)来实现信号量和互斥锁的功能。 ##### 3.1 包含头文件 要使用POSIX线程库中的信号量和互斥锁功能,首先需要包含`...

    3.线程间同步和通信之互斥锁(静态)

    在STM32平台上,RT-thread提供了一套完善的线程管理、信号量和互斥锁等同步机制。RT-thread中的互斥锁API包括`rt_mutex_init`、`rt_mutex_take`、`rt_mutex_release`和`rt_mutex_destroy`等函数。 1. `rt_mutex_...

    多线程 教程 各种锁 半成品的CAS 临界区 信号量 事件 互斥锁 队列

    在IT领域,多线程是并发编程中的重要概念,它允许多个任务在同一时间执行,提高了计算机系统的资源利用率和程序的响应速度...学习这些内容,开发者可以更好地理解和掌握多线程编程,有效地解决并发问题,提升软件性能。

    多线程互斥锁和条件变量demo

    在编程领域,多线程是实现并发执行任务的重要方式,特别是在多核处理器系统中,它能有效利用...对于初学者来说,分析并实践“多线程互斥锁和条件变量demo”是一个很好的起点,它可以帮助你更好地理解和运用这些工具。

    8. 递归互斥信号量.zip

    在FreeRTOS操作系统中,信号量是一种非常重要的同步和资源管理机制。递归互斥信号量是其中的一个特殊类型...同时,了解递归互斥信号量的工作原理也能帮助我们更好地设计和调试多线程程序,避免出现难以预料的并发问题。

    QT6之多线程控制-互斥量和信号量

    在多线程编程中,互斥量(Mutex)和信号量(Semaphore)是两种重要的同步机制,它们用于管理和保护共享资源,防止数据竞争和死锁等问题。本文将深入探讨在QT6中如何使用互斥量和信号量进行多线程控制。 首先,让...

    互斥锁、条件变量、信号量总结

    互斥锁、条件变量和信号量是操作系统中用于线程同步和资源管理的重要工具,尤其在多线程和多进程编程中发挥着关键作用。这些机制确保了共享资源的有序访问,防止数据竞争和死锁等问题的发生。 首先,互斥锁(Mutex...

    线程互斥和同步代码样本滴水三期信号量布置的作业

    信号量分为两种:二进制信号量(计数值只能为0或1,类似于互斥锁)和计数信号量(计数值可以大于1,允许多个线程同时访问)。 在滴水三期的作业中,你可能需要编写代码来演示如何使用信号量实现线程的同步。这可能...

    mutexes-variables-semaphores.rar_linux 线程锁_mutexes_锁和信号量

    在Linux系统中,多线程编程是实现并发执行的关键技术,而互斥锁(mutexes)、条件变量(condition variables)和信号量(semaphores)是确保线程安全和资源同步的重要工具。以下是对这些概念的详细解释: 1. 互斥锁...

    《临界区,互斥,信号量》

    临界区、互斥量和信号量都是用于线程间同步的重要工具。临界区提供了一种轻量级的锁定机制,适用于同一进程内线程之间的同步;互斥量支持更广泛的场景,包括跨进程的线程同步;而信号量则提供了一种更灵活的方式来...

    windowsC++多线程加锁信号量共享内存

    在"threadlock4"这个文件中,很可能包含了示例代码或者详细教程,演示了如何在Windows环境下使用C++的多线程、互斥锁、信号量和共享内存。通过阅读和理解这个文件,开发者可以学习到如何在实际项目中有效地管理和...

    使用信号量(Semaphore)实现线程的同步

    信号量(Semaphore)是操作系统中一种重要的同步机制,它用于管理多个线程对共享资源的访问,以防止并发执行时产生竞态条件。在多线程编程中,当多个线程试图同时访问一个有限的资源时,信号量可以帮助我们协调这些...

    boost库的线程例子和互斥锁

    它包括各种同步原语,如条件变量、信号量、事件和我们这里重点关注的互斥锁。 互斥锁(Mutex)是确保多线程安全的关键工具。在多线程环境中,当多个线程试图同时访问共享资源时,可能会引发数据不一致的问题。互斥...

    线程互斥--多线程学习

    2. **信号量**:信号量是一种更灵活的同步机制,它可以控制多个线程同时访问资源的数量。如果当前资源已被占用达到最大数量,新请求的线程会被挂起,直到有线程释放资源。 3. **条件变量**:条件变量允许线程在满足...

    互斥锁示例代码

    总之,互斥锁是保证多线程并发环境下数据安全的重要工具,通过理解其原理和正确使用,可以有效地实现线程同步,避免数据竞争,构建稳定可靠的多线程程序。在Linux系统编程中,熟悉互斥锁的使用是提升程序质量的关键...

Global site tag (gtag.js) - Google Analytics