- 浏览: 2180773 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
之前的一篇文章,我给出了关于多线程应用的几个例子:
都是基于Java里面Lock锁实现的,分别是:
(1)两个线程轮流打印奇数和偶数
(2)多个线程模拟买票
(3)模拟生产者消费者
今天再抛砖引玉,思考一下如何在多个线程中,轮流打印特定顺序的信息多少次。
这类问题其实并不难,只要掌握了Java里面线程协作和锁的知识,就可以轻而易举的搞定:
根据这些,我们来假设一个场景,使用三个线程轮流打印ABC字符串3次。
解决思路:
首先需要声明3个线程,我们可以分别叫A线程,B线程,C线程:
在这里面:
A线程仅仅负责打印A。
B线程仅仅负责打印B。
C线程仅仅负责打印C。
但是呢,他们必须是有顺序,也就是说A打印完之后,才能打印B,B打印完后才行打印C,这就涉及线程协作和通信的知识了,A线程打印完毕之后,要通知B线程打印,B线程打印完之后要通知C线程打印,如果有多轮的话,C线程打印完毕之后,还要通知A线程。以及控制多轮次数的终结,不能让程序陷入死循环之中。
在仔细理一下:
(1)首先三个线程启动后,一定是A线程先打印。如果是其他线程先启动,则必须等待,线程间的通信,我们用共享变量来解决。(本质是通过共享内存)
(2)A运行的时候,B和C都在等待
(3)B运行的时候,A和C都在等待
(4)C运行的时候,A和B都在等待
(5)A运行结束通知B运行
(6)B运行结束通知C运行
(7)C运行结束通知A运行
(8)同时,如果要控制几轮打印,则需要在运行时控制循环次数,因为C线程是每一轮的结束标志,循环次数的加和要在C线程里面做。
ok,主要的逻辑基本理清了,我们看下如何用代码实现,先看核心的类:
定义了共享的监视器对象,计数器,共享变量,然后定义了三个方法分别负责打印A,B,C,功能的实现主要用了synchronized + 监视器的wait,notifyAll方法。
``` static class PrintABC{ final Object monitor=new Object(); volatile int count=1;//轮次计数,从1开始,为了保证可见性,这里需要用volatile修饰 String id="A";//贡献的 int printCount ; public PrintABC(int printCount) { this.printCount = printCount; } public void printA() throws InterruptedException { while (count < printCount) { synchronized (monitor) { while (!id.equals("A")) { monitor.wait(); } System.out.println(Thread.currentThread().getName() + "打印: " + id); id = "B"; monitor.notifyAll(); } } } public void printB() throws InterruptedException { while (count < printCount) { synchronized (monitor) { while (!id.equals("B")) { monitor.wait(); } System.out.println(Thread.currentThread().getName() + "打印: " + id); id = "C"; monitor.notifyAll(); } } } public void printC() throws InterruptedException { while (count < printCount +1) {//最后一次终结线程,需要多加一次 synchronized (monitor) { while (!id.equals("C")) { monitor.wait(); } System.out.println(Thread.currentThread().getName() + "打印: " + id+"\n"); id = "A"; count=count+1; monitor.notifyAll(); } } } } ```
然后,我们看下,main方法如何编写:
``` public static void main(String[] args) { PrintABC printABC=new PrintABC(3); Thread t1=new Thread(()->{ try { printABC.printA(); } catch (InterruptedException e) { e.printStackTrace(); } }); t1.setName("A线程"); Thread t2=new Thread(()->{ try { printABC.printB(); } catch (InterruptedException e) { e.printStackTrace(); } }); t2.setName("B线程"); Thread t3=new Thread(()->{ try { printABC.printC(); } catch (InterruptedException e) { e.printStackTrace(); } }); t3.setName("C线程"); t2.start(); t3.start(); t1.start(); } ```
这里我们设置了3,也就是仅仅打印3轮,就终止程序。结果如下:
```java A线程打印: A B线程打印: B C线程打印: C A线程打印: A B线程打印: B C线程打印: C A线程打印: A B线程打印: B C线程打印: C ```
至此,这个问题就搞定了,我们思考下,因为这里面采用的是Java的内置锁synchronized来实现的,synchronized关键词虽然使用起来非常简单,但是由于它出现的早,本身也有一些缺点,细心的朋友可能已经发现,上面的通信代码处用的是:
``` monitor.notifyAll(); ```
注意这个地方,明明我们只需要唤醒一个线程,为什么需要notifyAll()而不是用notify(),这么做的主要目的是因为synchronized的监视器唤醒的线程是随机的,没办法精确到某个线程,所以它必须唤醒所有的线程,然后重新参与锁的竞争,这样就导致部分线程调度没必要的被交换了一次。
这个地方恰内置锁synchronized的一个弊端,这也是为什么在jdk5之后引入的Lock这样高级锁接口,其相比synchronized在加锁的时候,主要优点是:
(1)提供了公平和非公平调度
(2)可中断
(3)可提供非阻塞
(4)可超时
(5)提供了Condition更细粒度的,锁唤醒条件队列
本文中的例子,完全可以用Lock接口+Condition来达到更细粒度的锁控制,也就是A线程执行完之后,仅仅只唤醒B线程,没有必要把C线程也唤醒,感兴趣的朋友可以思考下怎么实现。
有什么问题可以扫码关注微信公众号:我是攻城师(woshigcs) 关注公众号的朋友,可以加入我们的:攻城师互助交流群,一起学习!
发表评论
-
记一次log4j不打印日志的踩坑记
2019-09-22 01:58 1556### 起因 前几天一个跑有java应用的生产集群(200多 ... -
在Java里面如何解决进退两难的jar包冲突问题?
2019-07-23 19:10 1227如上图所示: es api组件依赖guava18.0 ... -
如何轻松理解二叉树的深度遍历策略
2019-07-03 23:33 1119我们知道普通的线性数据结构如链表,数组等,遍历方式单一 ... -
为什么单线程Redis性能也很出色
2019-01-21 18:02 2201高性能的服务器,不一 ... -
如何将编程语言里面的字符串转成数字?
2019-01-11 23:23 2085将字符串转成数字在很 ... -
为什么Java里面String类是不可变的
2019-01-06 18:36 1663在Java里面String类型是不可变对象,这一点毫无疑问,那 ... -
关于Java里面volatile关键字的重排序
2019-01-04 18:49 1060Java里面volatile关键字主 ... -
聊聊Java里面的引用传递
2018-11-16 21:21 987长久以来,在Java语言里面一直有一个争论,就是Java语言到 ... -
理解计数排序算法的原理和实现
2018-10-11 10:03 2087计数排序(Counting sort) ... -
理解Java7和8里面HashMap+ConcurrentHashMap的扩容策略
2018-09-06 11:31 3385### 前言 理解HashMap和Con ... -
关于Java里面多线程同步的一些知识
2018-07-18 09:45 1102# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
Java单例模式之双检锁深入思考
2018-07-08 12:25 3287# Java单例模式之双检锁 ... -
关于Java里面多线程同步的一些知识
2018-07-08 12:23 1119# 关于Java里面多线程同步的一些知识 对于任何Java开 ... -
重新认识同步与异步,阻塞和非阻塞的概念
2018-07-06 14:30 1469# 重新认识同步与异步 ... -
线程的基本知识总结
2018-06-27 16:27 1057### (一)创建线程的方式 (1)实现Runnable接口 ... -
Java里面volatile关键字修饰引用变量的陷阱
2018-06-25 11:42 1384# Java里面volatile关键字修饰引用变量的陷阱 如 ... -
关于Java里面的字符串拼接,你了解多少?
2018-06-25 11:28 1364# 关于Java里面的字符串 ... -
深入理解Java内存模型的语义
2018-06-25 11:39 735### 前言 Java内存模型( ... -
如何证明Java多线程中的成员变量数据是互不可见的
2018-06-21 10:09 1496前面的几篇文章主要介绍了Java的内存模型,进程和线程的定义, ... -
给Java字节码加上”翅膀“的JIT编译器
2018-06-20 10:12 1034# 给Java字节码加上”翅 ...
相关推荐
java多线程每个线程挨着打印ABC的4种实现方式,有4个线程t1、t2、t3、t4,t1打印A后t2打印A再t3打印A再t4打印A,然后从新回到t1打印B再t2打印B...t4打印B... 4个线程轮流打印abc... 一个线程可以理解为一个人,打印...
使用多线程和阻塞队列实现了ABC字母按顺序轮流打印
本文将详细讲解如何使用Java实现多线程轮流打印1-100的数字,以及在此过程中遇到的并发问题及其解决方案。 首先,我们要理解基本的Java线程创建和运行方式。在示例代码中,通过`Thread`类和`Runnable`接口创建了多...
本文将详细解析如何使用C++11的标准线程语法来实现两个线程轮流打印整数,其中一个线程打印奇数,另一个线程打印偶数,同时涉及到线程同步的关键技术——互斥量和条件变量。 首先,为了确保线程安全,我们需要使用...
在Java编程中,多线程同步是一个常见的挑战,特别是在需要线程按照特定顺序执行任务时。本主题聚焦于如何使用Java实现10个线程按照顺序打印数字1到100。这种问题通常通过线程间通信和同步机制来解决,如`...
同步是多线程编程中的关键概念,它确保在特定时刻只有一个线程可以访问共享资源,以防止数据竞争和不一致。在我们的实验中,缓冲区就是共享资源,需要进行同步控制。C#提供了多种同步机制,如锁(`lock`关键字)、...
"多线程调试打印日志类"是一个专门设计用于在多线程环境中记录和打印日志的C++类。此类实现了一个单例模式,确保在整个应用程序中只有一个实例存在,从而避免了资源竞争和日志混乱的问题。 首先,单例模式是一种...
Java多线程连续打印abc实现方法详解是 Java 编程语言中的一种常见问题,旨在解决三个线程同时执行,要求打印出10个连着的abc的难题。该问题的解决方案需要使用同步机制来确保三个线程的顺序执行。 知识点一:多线程...
本示例中的"java代码-三个线程轮流输出abc"是一个经典的多线程同步问题,通常被称为"生产者消费者问题"的一个变种。在这个问题中,有三个线程分别代表A、B、C三个角色,它们需要按照特定顺序(ABC、BCA、CAB、...)...
本资源"ConsoleApp1"是一个C#实现的多线程示例,它演示了如何在多线程环境中顺序打印1到100的数字。在多线程环境下实现顺序打印看似简单,实则涉及到线程同步和控制的问题,这通常通过各种同步原语来实现。在这个...
在处理文件打印这样的任务时,多线程可以并行地读取、处理和打印多个文件,从而提高效率。 在“文件打印问题”中,可能会遇到的一个关键问题是资源竞争。当多个线程尝试同时访问和修改同一个文件时,如果没有适当的...
在这个"多线程依次循环打印26个英文字母"的问题中,我们主要关注如何在多个线程之间同步操作,确保字母按照顺序正确地输出。这里涉及了`条件队列`和`lock`两个关键概念。 首先,让我们理解一下`多线程`。在单核...
在C#编程中,多线程技术是一种强大的工具,它允许程序同时执行多个任务,从而提高效率和响应性。在处理耗时操作如打印时,多线程尤其有用,可以确保用户界面不会被阻塞,提供更好的用户体验。本文将深入探讨如何在C#...
在CUDA编程中,"向量在同一个块中用多个线程执行"是一种并行计算策略,主要用于提升GPU的计算效率。CUDA(Compute Unified Device Architecture)是NVIDIA推出的一种编程模型,它允许程序员直接利用GPU的强大计算...
在`asnc-print-different-logfile`这个压缩包中,可能包含了一个示例项目,用于演示如何配置和使用Log4j2实现异步多线程打印。项目可能包含以下元素: 1. `pom.xml`:Maven项目的配置文件,定义了依赖项和构建指令...
测试这个多线程互斥的例子,我们可以创建多个线程,每个线程分别调用`Increment`或`Decrement`方法,然后观察`GetValue`返回的值是否正确反映了操作的顺序。在`多线程test`这个项目中,很可能包含了这样的测试代码,...
在标题"socket 一个服务器对应多个客户端使用多线程"中,提到的是使用Socket编程来设计一个服务器,该服务器能够同时处理来自多个客户端的连接请求,这通常被称为“一对一”或“一对多”模型。在Linux环境下,这种...
每个线程会有一个特定的打印序列,例如线程A打印"ABC",线程B打印"DEF",线程C打印"GHI"。为了实现交错输出,我们需要控制线程的执行顺序,确保它们在特定时刻能够交替访问共享资源(在这种情况下,共享资源是打印...
一个简单的例子,C#多线程实现调用外部程序并获取打印结果 一个简单的例子,C#多线程实现调用外部程序并获取打印结果 一个简单的例子,C#多线程实现调用外部程序并获取打印结果 一个简单的例子,C#多线程实现调用...