多线程访问共同资源(队列,多线程,锁机制)

简介: 模拟场景:main方法为网络请求线程(也叫生产者线程),在网络请求线程中开启四个线程(消费者线程),进行高效处理队列中的共同资源(生产者线程生产的共同资源),等待资源处理完毕,网络请求线程执行结束,响应客户端。

模拟场景:main方法为网络请求线程(也叫生产者线程),在网络请求线程中开启四个线程(消费者线程),进行高效处理队列中的共同资源(生产者线程生产的共同资源),等待资源处理完毕,网络请求线程执行结束,响应客户端。

消费者线程的线程体

  1 import java.text.SimpleDateFormat;
  2 import java.util.Date;
  3 import java.util.concurrent.BlockingQueue;
  4 import java.util.concurrent.LinkedBlockingQueue;
  5 import java.util.concurrent.TimeUnit;
  6 
  7 /**
  8  * 【1】实现Runnable接口,重写run方法。
  9  * 【2】run方法内的逻辑代码就是线程体
 10  * 【3】创建线程类的对象
 11  * 【4】创建线程类的代理对象
 12  * 【5】代理对象调用start(),启动线程
 13  * @author it-c-1201
 14  *
 15  */
 16 public class MyThread implements Runnable{
 17     //多线程访问共同资源的队列
 18     private  BlockingQueue<String> a = new LinkedBlockingQueue<String>();
 19     
 20     //队列中共同资源的个数
 21     private Integer count=0;
 22     
 23     //线程锁
 24     private Object object=new Object();
 25     
 26     //生产者生产完成标示<false 未生产完成,true 生产完成>
 27     private boolean flag=false;
 28     
 29     //线程类构造器。
 30     public MyThread(BlockingQueue<String> a){
 31         this.a=a;
 32     }
 33     
 34     //获取线程锁对象
 35     public Object getObjectByLock(){
 36         return this.object;
 37     }
 38     
 39     //标志生产者生产结束
 40     public void setFlag(){
 41         this.flag=true;
 42     }
 43 
 44     //队列数据加一个
 45     public void setCount(){
 46         //当出现队列数据小于1的情况,恢复队列中数据个数为0
 47         if(count<0){
 48             count=0;
 49         }
 50         count++;
 51     }
 52     
 53     //线程体
 54     public void run() {
 55         //消费
 56         while(true){
 57             //获取当前线程名字
 58             String threadName=Thread.currentThread().getName();
 59             
 60             //资源处理完毕&&生产者停止生产,则跳出死循环
 61             if(count==0&&flag){
 62                 break;
 63             }
 64             
 65             
 66             String pollInteger;
 67             try {
 68                 //从队列中获取数据。如果没有数据等待100毫秒,100毫秒后还是无数据,返回null
 69                 pollInteger = a.poll(100, TimeUnit.MILLISECONDS);
 70                 
 71                 //如果取出的数据为空,则暂停本次循环,进行下次循环(后边代码不执行)
 72                 if(pollInteger==null){
 73                     continue;
 74                 }
 75                 
 76                 //如果队列中资源个数为0,则暂停本次循环,进行下次循环
 77                 if(count==0||count<0){
 78                     continue;
 79                 }
 80                 
 81                 //说明从队列中取出数据,队列中数据个数减一
 82                 count--;    
 83                 
 84                 //获取执行时间点
 85                 SimpleDateFormat aDateFormat=new SimpleDateFormat("HH:mm:ss SS");
 86                 Date date=new Date();
 87                 String dateString=aDateFormat.format(date);
 88                 //模拟消费队列中获取的数据
 89                 System.out.println("MyThread.run(-->)"+threadName+"【"+pollInteger+"】  时间: "+dateString);
 90             } catch (InterruptedException e) {
 91                 // TODO Auto-generated catch block
 92                 e.printStackTrace();
 93             }
 94             
 95         }
 96         
 97         //唤醒所有线程
 98         synchronized(object){
 99             //唤醒该锁锁住的所有线程【证明没有数据要处理了,main方法中挂起的线程(模拟的网络请求线程)被唤醒,main方法执行结束】
100             object.notifyAll();
101             String tString=Thread.currentThread().getName();
102             System.out.println("MyThread.run(-->)"+tString+"notfyAll()");
103         }
104         
105     }
106     
107     
108 }
View Code

main方法(模拟的网络请求线程)

 1 import java.text.SimpleDateFormat;
 2 import java.util.Date;
 3 import java.util.concurrent.BlockingQueue;
 4 import java.util.concurrent.LinkedBlockingQueue;
 5 
 6 
 7 public class Test {
 8     
 9     //模拟多线程消费的共同资源
10     private static BlockingQueue<String> a = new LinkedBlockingQueue<String>();
11     
12     //模拟的网络请求来要执行的方法
13     public static void main(String[] args) {
14         //新建线程对象
15         MyThread myThread=new MyThread(a);
16         
17         
18         //开启四个消费线程
19         for(int i=0;i<4;i++){
20             Thread aThread=new Thread(myThread);
21             aThread.setName("THREAD"+i);
22             aThread.start();
23         }
24         
25         //模拟生产线程
26         try {
27             for(int i=0;i<100;i++){
28                     //往队列中加数据
29                     a.put(i+"sxf");
30                     //队列中数据个数加1
31                     myThread.setCount();
32                 }
33             } catch (InterruptedException e) {
34                 // TODO Auto-generated catch block
35                 e.printStackTrace();
36             }finally{
37                 myThread.setFlag();
38             }
39                         
40                 
41         
42         //模拟当生产完毕后,网络请求线程也叫生产线程被阻塞
43         synchronized (myThread.getObjectByLock()) {
44             try {
45                 myThread.getObjectByLock().wait();
46             } catch (InterruptedException e) {
47                 // TODO Auto-generated catch block
48                 e.printStackTrace();
49             }
50         }
51         
52         //模拟网络请求线程被唤醒后,执行完毕,向客户端响应数据
53         SimpleDateFormat aDateFormat=new SimpleDateFormat("HH:mm:ss SS");
54         Date date=new Date();
55         String dateString=aDateFormat.format(date);
56         System.out.println("Test.main(完成时间:)"+dateString);
57     }
58 }
View Code

 测试结果

  1 MyThread.run(-->)THREAD2【2sxf】  时间: 19:39:06 127
  2 MyThread.run(-->)THREAD3【0sxf】  时间: 19:39:06 127
  3 MyThread.run(-->)THREAD0【1sxf】  时间: 19:39:06 127
  4 MyThread.run(-->)THREAD2【4sxf】  时间: 19:39:06 128
  5 MyThread.run(-->)THREAD0【6sxf】  时间: 19:39:06 128
  6 MyThread.run(-->)THREAD1【3sxf】  时间: 19:39:06 127
  7 MyThread.run(-->)THREAD2【7sxf】  时间: 19:39:06 128
  8 MyThread.run(-->)THREAD0【8sxf】  时间: 19:39:06 128
  9 MyThread.run(-->)THREAD3【5sxf】  时间: 19:39:06 128
 10 MyThread.run(-->)THREAD2【10sxf】  时间: 19:39:06 128
 11 MyThread.run(-->)THREAD3【12sxf】  时间: 19:39:06 129
 12 MyThread.run(-->)THREAD1【9sxf】  时间: 19:39:06 128
 13 MyThread.run(-->)THREAD3【14sxf】  时间: 19:39:06 129
 14 MyThread.run(-->)THREAD1【15sxf】  时间: 19:39:06 129
 15 MyThread.run(-->)THREAD3【16sxf】  时间: 19:39:06 129
 16 MyThread.run(-->)THREAD2【13sxf】  时间: 19:39:06 129
 17 MyThread.run(-->)THREAD0【11sxf】  时间: 19:39:06 129
 18 MyThread.run(-->)THREAD3【18sxf】  时间: 19:39:06 129
 19 MyThread.run(-->)THREAD2【19sxf】  时间: 19:39:06 129
 20 MyThread.run(-->)THREAD0【20sxf】  时间: 19:39:06 129
 21 MyThread.run(-->)THREAD3【21sxf】  时间: 19:39:06 129
 22 MyThread.run(-->)THREAD2【22sxf】  时间: 19:39:06 129
 23 MyThread.run(-->)THREAD1【17sxf】  时间: 19:39:06 129
 24 MyThread.run(-->)THREAD3【24sxf】  时间: 19:39:06 129
 25 MyThread.run(-->)THREAD0【23sxf】  时间: 19:39:06 129
 26 MyThread.run(-->)THREAD2【25sxf】  时间: 19:39:06 129
 27 MyThread.run(-->)THREAD1【26sxf】  时间: 19:39:06 129
 28 MyThread.run(-->)THREAD2【29sxf】  时间: 19:39:06 129
 29 MyThread.run(-->)THREAD0【28sxf】  时间: 19:39:06 129
 30 MyThread.run(-->)THREAD3【27sxf】  时间: 19:39:06 129
 31 MyThread.run(-->)THREAD1【30sxf】  时间: 19:39:06 129
 32 MyThread.run(-->)THREAD2【31sxf】  时间: 19:39:06 130
 33 MyThread.run(-->)THREAD0【32sxf】  时间: 19:39:06 130
 34 MyThread.run(-->)THREAD3【33sxf】  时间: 19:39:06 130
 35 MyThread.run(-->)THREAD1【34sxf】  时间: 19:39:06 130
 36 MyThread.run(-->)THREAD2【35sxf】  时间: 19:39:06 130
 37 MyThread.run(-->)THREAD0【36sxf】  时间: 19:39:06 130
 38 MyThread.run(-->)THREAD3【37sxf】  时间: 19:39:06 130
 39 MyThread.run(-->)THREAD1【38sxf】  时间: 19:39:06 130
 40 MyThread.run(-->)THREAD2【39sxf】  时间: 19:39:06 130
 41 MyThread.run(-->)THREAD0【40sxf】  时间: 19:39:06 130
 42 MyThread.run(-->)THREAD3【41sxf】  时间: 19:39:06 130
 43 MyThread.run(-->)THREAD1【42sxf】  时间: 19:39:06 130
 44 MyThread.run(-->)THREAD2【43sxf】  时间: 19:39:06 130
 45 MyThread.run(-->)THREAD0【44sxf】  时间: 19:39:06 130
 46 MyThread.run(-->)THREAD3【45sxf】  时间: 19:39:06 130
 47 MyThread.run(-->)THREAD1【46sxf】  时间: 19:39:06 130
 48 MyThread.run(-->)THREAD2【47sxf】  时间: 19:39:06 130
 49 MyThread.run(-->)THREAD0【48sxf】  时间: 19:39:06 130
 50 MyThread.run(-->)THREAD3【49sxf】  时间: 19:39:06 130
 51 MyThread.run(-->)THREAD1【50sxf】  时间: 19:39:06 130
 52 MyThread.run(-->)THREAD2【51sxf】  时间: 19:39:06 130
 53 MyThread.run(-->)THREAD0【52sxf】  时间: 19:39:06 130
 54 MyThread.run(-->)THREAD3【53sxf】  时间: 19:39:06 130
 55 MyThread.run(-->)THREAD1【54sxf】  时间: 19:39:06 130
 56 MyThread.run(-->)THREAD2【55sxf】  时间: 19:39:06 130
 57 MyThread.run(-->)THREAD0【56sxf】  时间: 19:39:06 130
 58 MyThread.run(-->)THREAD3【57sxf】  时间: 19:39:06 130
 59 MyThread.run(-->)THREAD1【58sxf】  时间: 19:39:06 130
 60 MyThread.run(-->)THREAD3【61sxf】  时间: 19:39:06 131
 61 MyThread.run(-->)THREAD2【59sxf】  时间: 19:39:06 131
 62 MyThread.run(-->)THREAD0【60sxf】  时间: 19:39:06 131
 63 MyThread.run(-->)THREAD1【62sxf】  时间: 19:39:06 131
 64 MyThread.run(-->)THREAD3【63sxf】  时间: 19:39:06 131
 65 MyThread.run(-->)THREAD0【65sxf】  时间: 19:39:06 131
 66 MyThread.run(-->)THREAD1【66sxf】  时间: 19:39:06 131
 67 MyThread.run(-->)THREAD3【67sxf】  时间: 19:39:06 131
 68 MyThread.run(-->)THREAD0【68sxf】  时间: 19:39:06 131
 69 MyThread.run(-->)THREAD1【69sxf】  时间: 19:39:06 131
 70 MyThread.run(-->)THREAD3【70sxf】  时间: 19:39:06 131
 71 MyThread.run(-->)THREAD2【64sxf】  时间: 19:39:06 131
 72 MyThread.run(-->)THREAD0【71sxf】  时间: 19:39:06 131
 73 MyThread.run(-->)THREAD2【74sxf】  时间: 19:39:06 132
 74 MyThread.run(-->)THREAD3【73sxf】  时间: 19:39:06 131
 75 MyThread.run(-->)THREAD0【75sxf】  时间: 19:39:06 132
 76 MyThread.run(-->)THREAD2【76sxf】  时间: 19:39:06 132
 77 MyThread.run(-->)THREAD0【78sxf】  时间: 19:39:06 132
 78 MyThread.run(-->)THREAD2【79sxf】  时间: 19:39:06 132
 79 MyThread.run(-->)THREAD0【80sxf】  时间: 19:39:06 132
 80 MyThread.run(-->)THREAD2【81sxf】  时间: 19:39:06 132
 81 MyThread.run(-->)THREAD0【82sxf】  时间: 19:39:06 132
 82 MyThread.run(-->)THREAD2【83sxf】  时间: 19:39:06 132
 83 MyThread.run(-->)THREAD0【84sxf】  时间: 19:39:06 132
 84 MyThread.run(-->)THREAD2【85sxf】  时间: 19:39:06 132
 85 MyThread.run(-->)THREAD0【86sxf】  时间: 19:39:06 132
 86 MyThread.run(-->)THREAD2【87sxf】  时间: 19:39:06 132
 87 MyThread.run(-->)THREAD0【88sxf】  时间: 19:39:06 132
 88 MyThread.run(-->)THREAD2【89sxf】  时间: 19:39:06 132
 89 MyThread.run(-->)THREAD0【90sxf】  时间: 19:39:06 132
 90 MyThread.run(-->)THREAD2【91sxf】  时间: 19:39:06 132
 91 MyThread.run(-->)THREAD1【72sxf】  时间: 19:39:06 131
 92 MyThread.run(-->)THREAD0【92sxf】  时间: 19:39:06 133
 93 MyThread.run(-->)THREAD3【77sxf】  时间: 19:39:06 132
 94 MyThread.run(-->)THREAD2【93sxf】  时间: 19:39:06 133
 95 MyThread.run(-->)THREAD0【95sxf】  时间: 19:39:06 133
 96 MyThread.run(-->)THREAD1【94sxf】  时间: 19:39:06 133
 97 MyThread.run(-->)THREAD3【96sxf】  时间: 19:39:06 133
 98 MyThread.run(-->)THREAD0【98sxf】  时间: 19:39:06 133
 99 MyThread.run(-->)THREAD2【97sxf】  时间: 19:39:06 133
100 MyThread.run(-->)THREAD3notfyAll()
101 MyThread.run(-->)THREAD2notfyAll()
102 MyThread.run(-->)THREAD0notfyAll()
103 MyThread.run(-->)THREAD1【99sxf】  时间: 19:39:06 133
104 MyThread.run(-->)THREAD1notfyAll()
105 Test.main(完成时间:)19:39:06 133
View Code

 

相关文章
|
2月前
|
Java 开发者
在Java多线程编程中,选择合适的线程创建方法至关重要
【10月更文挑战第20天】在Java多线程编程中,选择合适的线程创建方法至关重要。本文通过案例分析,探讨了继承Thread类和实现Runnable接口两种方法的优缺点及适用场景,帮助开发者做出明智的选择。
22 2
|
2月前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
35 2
|
27天前
|
数据采集 Java Python
爬取小说资源的Python实践:从单线程到多线程的效率飞跃
本文介绍了一种使用Python从笔趣阁网站爬取小说内容的方法,并通过引入多线程技术大幅提高了下载效率。文章首先概述了环境准备,包括所需安装的库,然后详细描述了爬虫程序的设计与实现过程,包括发送HTTP请求、解析HTML文档、提取章节链接及多线程下载等步骤。最后,强调了性能优化的重要性,并提醒读者遵守相关法律法规。
58 0
|
2月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
56 1
C++ 多线程之初识多线程
|
2月前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
26 3
|
2月前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
41 1
|
2月前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
47 1
|
2月前
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
29 1
|
3月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
2月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
71 6