版权声明:原创作品,谢绝转载!否则将追究法律责任。

Disruptor是一个优秀的并发框架,可以实现单个或多个生产者生产消息,单个或多个消费者消息,且消费者之间可以存在消费消息的依赖关系。网上其他博客往往仅针对框架的一部分使用示例进行了介绍,对于某些场景下介绍并不完全:如多生产者间复杂的依赖关系的使用编码。

本文尽可能对Disruptor的所有使用场景进行总结,如有不全之处欢迎指出,请谅解。

具体关于Disruptor的原理,参见:http://ifeve.com/disruptor/,本文不在赘述。

Disruptor类的handleEventsWith,handleEventsWithWorkerPool方法的联系及区别

在disruptor框架调用start方法之前,往往需要将消息的消费者指定给disruptor框架。

常用的方法是:disruptor.handleEventsWith(EventHandler ... handlers),将多个EventHandler的实现类传入方法,封装成一个EventHandlerGroup,实现多消费者消费。

disruptor的另一个方法是:disruptor.handleEventsWithWorkerPool(WorkHandler ... handlers),将多个WorkHandler的实现类传入方法,封装成一个EventHandlerGroup实现多消费者消费。

两者共同点都是,将多个消费者封装到一起,供框架消费消息。

不同点在于,

1. 对于某一条消息m,handleEventsWith方法返回的EventHandlerGroup,Group中的每个消费者都会对m进行消费,各个消费者之间不存在竞争。handleEventsWithWorkerPool方法返回的EventHandlerGroup,Group的消费者对于同一条消息m不重复消费;也就是,如果c0消费了消息m,则c1不再消费消息m。

2. 传入的形参不同。对于独立消费的消费者,应当实现EventHandler接口。对于不重复消费的消费者,应当实现WorkHandler接口。

因此,根据消费者集合是否独立消费消息,可以对不同的接口进行实现。也可以对两种接口同时实现,具体消费流程由disruptor的方法调用决定。

在进行场景分析之前,首先定义公共的生产者Producer,消费者OrderHandler1,消息Order,消息工厂OrderFactory。定义分别如下:

package liuqiang.complex.common;

public class Order {

    private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
package liuqiang.complex.common;

import com.lmax.disruptor.EventFactory;

public class OrderFactory implements EventFactory<Order> {
@Override
public Order newInstance() {
return new Order();
}
}
package liuqiang.complex.common;

import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.WorkHandler; //EventHandler用于EventHandlerGroup,WorkHandler用于WorkPool。同时实现两接口,该类对象可同时用于EventHandlerGroup和WorkPool
public class OrderHandler1 implements EventHandler<Order>, WorkHandler<Order> {
private String consumerId;
public OrderHandler1(String consumerId){
this.consumerId = consumerId;
} //EventHandler的方法
@Override
public void onEvent(Order order, long sequence, boolean endOfBatch) throws Exception {
System.out.println("OrderHandler1 " + this.consumerId + ",消费信息:" + order.getId());
} //WorkHandler的方法
@Override
public void onEvent(Order order) throws Exception {
System.out.println("OrderHandler1 " + this.consumerId + ",消费信息:" + order.getId());
}
}
package liuqiang.complex.common;

import com.lmax.disruptor.RingBuffer;

public class Producer {

    private final RingBuffer<Order> ringBuffer;
public Producer(RingBuffer<Order> ringBuffer){
this.ringBuffer = ringBuffer;
}
public void onData(String data){
long sequence = ringBuffer.next();
try {
Order order = ringBuffer.get(sequence);
order.setId(data);
} finally {
ringBuffer.publish(sequence);
}
}
}

下面定义两种不同的消费者集合关系:

场景一:单生产者单消费者

package liuqiang.complex.single;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.Executors; public class Main1 { //单生产者模式,单消费者模式
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
//设置一个消费者
disruptor.handleEventsWith(new OrderHandler1("1"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

这种情况最为简单,单生产者,仅需在Disruptor初始化时,传入ProducerType.SINGLE即可。使用disruptor.handleEventsWith传入单消费者。Thread.sleep方法调用是为了保证,在调用disruptor.shutdown方法前,所有的消费者线程都已经启动,防止shutdown失效的问题。具体问题详见本人另一篇博客:Disruptor中shutdown方法失效,及产生的不确定性源码分析。

输出结果如下:

OrderHandler1 1,消费信息:0
OrderHandler1 1,消费信息:1
OrderHandler1 1,消费信息:2

场景二:单生产者多消费者,多消费者间形成依赖关系,每个依赖节点只有一个消费者。

package liuqiang.complex.single;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.EventHandlerGroup;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.*; import java.util.concurrent.Executors; public class Main2 { //单生产者,多消费者,但多消费者间形成依赖关系,每个依赖节点单线程。
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
//多个消费者间形成依赖关系,每个依赖节点的消费者为单线程。
disruptor.handleEventsWith(new OrderHandler1("1")).then(new OrderHandler1("2"), new OrderHandler1("3")).then(new OrderHandler1("4"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

四个消费者之间的依赖图如下:

消费者C2、C3只有在C1消费完消息m后,才能消费m。消费者C4只有在C2、C3消费完m后,才能消费该消息。

可能的输出结果如下(可能因为线程执行先后顺序不同略有区别,但输出一定满足相关依赖约束):

OrderHandler1 1,消费信息:0
OrderHandler1 1,消费信息:1
OrderHandler1 2,消费信息:0
OrderHandler1 3,消费信息:0
OrderHandler1 1,消费信息:2
OrderHandler1 2,消费信息:1
OrderHandler1 2,消费信息:2
OrderHandler1 3,消费信息:1
OrderHandler1 3,消费信息:2
OrderHandler1 4,消费信息:0
OrderHandler1 4,消费信息:1
OrderHandler1 4,消费信息:2

场景三:单生产者,多消费者模式。多消费者对于消息不重复消费。

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.EventHandlerGroup;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.*; import java.util.concurrent.Executors; public class Main3 { //单生产者,多消费者模式。多消费者对于消息不重复消费。例如:1线程消费了消息0,则2线程只能从0后面的消息消费,不能对消息0进行消费。
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
/*
* 该方法传入的消费者需要实现WorkHandler接口,方法的内部实现是:先创建WorkPool,然后封装WorkPool为EventHandlerPool返回。
* 消费者1、2对于消息的消费有时有竞争,保证同一消息只能有一个消费者消费
*/
disruptor.handleEventsWithWorkerPool(new OrderHandler1("1"), new OrderHandler1("2"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

调用handleEventsWithWorkerPool形成WorkerPool,并进一步封装成EventHandlerGroup。对于同一条消息,两消费者不重复消费。

可能输出结果如下:

OrderHandler1 1,消费信息:0
OrderHandler1 2,消费信息:1
OrderHandler1 1,消费信息:2

场景四:单生产者多消费者,多消费者对于消息m独立消费。

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.Executors; public class Main4 { //单生产者,多消费者模式。多消费者对于消息独立消费。例如:对于消息m,两个消费者都要对其进行消费。
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
/*
* 两个消费者创建EventHandlerGroup。该消费者需要实现EventHandler类。两个消费者对于RingBuffer中的每个消息,都独立消费一次。
* 两个消费者在消费消息的过程中,各自独立,不产生竞争。
*/
disruptor.handleEventsWith(new OrderHandler1("1"), new OrderHandler1("2"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

可能输出结果如下:

OrderHandler1 1,消费信息:0
OrderHandler1 2,消费信息:0
OrderHandler1 2,消费信息:1
OrderHandler1 2,消费信息:2
OrderHandler1 1,消费信息:1
OrderHandler1 1,消费信息:2

场景五:单生产者,多消费者间存在依赖关系的模式。消费者1、2消息独立消费。消费者3、4仅能消费1、2均消费过的消息,消费者5仅能消费3、4均消费过的消息

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.Executors; public class Main5 { //单生产者,多消费者间存在依赖关系的模式。消费者1、2组成EventHandlerGroup,消息独立消费。消费者3、4仅能消费1、2均消费过的消息,且独立消费。消费者5仅能消费3、4均消费过的消息
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
//相当于在各个EventHandlerGroup之间进行级联,形成依赖关系。
disruptor.handleEventsWith(new OrderHandler1("1"), new OrderHandler1("2")).then(new OrderHandler1("3"), new OrderHandler1("4")).then(new OrderHandler1("5"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

消费者之间的依赖关系如下:

可能的输出结果如下:

OrderHandler1 2,消费信息:0
OrderHandler1 1,消费信息:0
OrderHandler1 1,消费信息:1
OrderHandler1 1,消费信息:2
OrderHandler1 2,消费信息:1
OrderHandler1 2,消费信息:2
OrderHandler1 3,消费信息:0
OrderHandler1 3,消费信息:1
OrderHandler1 3,消费信息:2
OrderHandler1 4,消费信息:0
OrderHandler1 4,消费信息:1
OrderHandler1 4,消费信息:2
OrderHandler1 5,消费信息:0
OrderHandler1 5,消费信息:1
OrderHandler1 5,消费信息:2

场景六:单生产者,多消费者。多消费者之间不重复消费,且不同的消费者WorkPool之间存在依赖关系。

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.Executors; public class Main6 { /*
* 单生产者,多消费者。多消费者之间不重复消费,且不同的消费者WorkPool之间存在依赖关系。
* 消费者1、2不重复消费消息,消费者3、4不重复消费1或者2消费过的消息,消费者5消费消费者3或4消费过的消息。
*/
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
disruptor.handleEventsWithWorkerPool(new OrderHandler1("1"), new OrderHandler1("2")).thenHandleEventsWithWorkerPool(new OrderHandler1("3"), new OrderHandler1("4")).thenHandleEventsWithWorkerPool(new OrderHandler1("5"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

消费者之间的依赖图如下所示:

可能的输出结果如下:

OrderHandler1 2,消费信息:0
OrderHandler1 1,消费信息:1
OrderHandler1 2,消费信息:2
OrderHandler1 3,消费信息:0
OrderHandler1 3,消费信息:2
OrderHandler1 4,消费信息:1
OrderHandler1 5,消费信息:0
OrderHandler1 5,消费信息:1
OrderHandler1 5,消费信息:2

场景七:单生产者,多消费者模式。消费者1、2不重复消费消息,消费者3、4消费消费者1或2消费过的消息,且独立重复消费。消费者5消费消费者3、4均消费过的消息。

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.Executors; public class Main7 { //单生产者,多消费者模式。消费者1、2不重复消费消息,消费者3、4消费消费者1或2消费过的消息,且独立重复消费。消费者5消费消费者3、4均消费过的消息。
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
disruptor.handleEventsWithWorkerPool(new OrderHandler1("1"), new OrderHandler1("2")).then(new OrderHandler1("3"), new OrderHandler1("4")).then(new OrderHandler1("5"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (long l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

消费者之间的依赖图如下:

可能的输出结果如下:

OrderHandler1 1,消费信息:1
OrderHandler1 2,消费信息:0
OrderHandler1 1,消费信息:2
OrderHandler1 4,消费信息:0
OrderHandler1 4,消费信息:1
OrderHandler1 3,消费信息:0
OrderHandler1 4,消费信息:2
OrderHandler1 3,消费信息:1
OrderHandler1 3,消费信息:2
OrderHandler1 5,消费信息:0
OrderHandler1 5,消费信息:1
OrderHandler1 5,消费信息:2

场景八:单生产者,多消费者模式。消费者1、2独立消费每一条消息,消费者3、4不重复消费消费者1、2均处理过的消息,消费者5消费消费者3或4消费过的消息

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.Executors; public class Main8 { //单生产者,多消费者模式。消费者1、2独立消费每一条消息,消费者3、4不重复消费消费者1、2均处理过的消息,消费者5消费消费者3或4消费过的消息
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());
disruptor.handleEventsWith(new OrderHandler1("1"), new OrderHandler1("2")).thenHandleEventsWithWorkerPool(new OrderHandler1("3"), new OrderHandler1("4")).then(new OrderHandler1("5"));
disruptor.start();
RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
Producer producer = new Producer(ringBuffer);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
producer.onData(l + "");
}
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

消费者间的依赖图如下:

可能的输出结果如下:

OrderHandler1 2,消费信息:0
OrderHandler1 2,消费信息:1
OrderHandler1 2,消费信息:2
OrderHandler1 1,消费信息:0
OrderHandler1 1,消费信息:1
OrderHandler1 1,消费信息:2
OrderHandler1 3,消费信息:0
OrderHandler1 3,消费信息:1
OrderHandler1 3,消费信息:2
OrderHandler1 5,消费信息:0
OrderHandler1 5,消费信息:1
OrderHandler1 5,消费信息:2

场景九:多生产者,单消费者模式

该场景较为简单,只需将ProducerType.SINGLE改为ProducerType.MULTI,并且编写多线程生产者的相关代码即可。

package liuqiang.complex.multi;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import liuqiang.complex.common.Order;
import liuqiang.complex.common.OrderFactory;
import liuqiang.complex.common.OrderHandler1;
import liuqiang.complex.common.Producer; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors; public class Main9 { //多生产者,单消费者版本。三个生产者独立生产消息。
public static void main(String[] args) throws Exception {
EventFactory<Order> factory = new OrderFactory();
int ringBufferSize = 1024 * 1024;
//ProducerType要设置为MULTI,后面才可以使用多生产者模式
Disruptor<Order> disruptor =
new Disruptor<Order>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.MULTI, new YieldingWaitStrategy());
//简化问题,设置为单消费者模式,也可以设置为多消费者及消费者间多重依赖。
disruptor.handleEventsWith(new OrderHandler1("1"));
disruptor.start();
final RingBuffer<Order> ringBuffer = disruptor.getRingBuffer();
//判断生产者是否已经生产完毕
final CountDownLatch countDownLatch = new CountDownLatch(3);
//单生产者,生产3条数据
for (int l = 0; l < 3; l++) {
Thread thread = new Thread() {
@Override
public void run() {
for(int i = 0; i < 3; i++) {
new Producer(ringBuffer).onData(Thread.currentThread().getName() + "'s " + i + "th message");
}
countDownLatch.countDown();
}
};
thread.setName("producer thread " + l);
thread.start();
}
countDownLatch.await();
//为了保证消费者线程已经启动,留足足够的时间。具体原因详见另一篇博客:disruptor的shutdown失效问题
Thread.sleep(1000);
disruptor.shutdown();
}
}

以上是,对disruptor的各个使用场景的简单介绍。

后面会写博客针对Disruptor的各部分源码做一分析,详细介绍其消费者之间依赖关系的实现机制、单生产者、多生产者之间的不同实现方式等。

Disruptor框架中生产者、消费者的各种复杂依赖场景下的使用总结的更多相关文章

  1. 关于java中生产者消费者模式的理解

    在说生产者消费者模式之前,我觉得有必要理解一下 Obj.wait(),与Obj.notify()方法.wait()方法是指在持有对象锁的线程调用此方法时,会释放对象锁,同时休眠本线程.notify() ...

  2. selenium自动化实例: 多层框架中关于iframe的定位,以及select下拉框选择

    对于一个自动化的初学者来说会很常见的遇到元素明明存在却始终定位不到, 从而导致脚本报错,当然定位不到元素的原因很多, 其中一种就是多层框架iframe导致的 下方截图示意: 下方为写脚本时候的示例并其 ...

  3. react中createFactory, createClass, createElement分别在什么场景下使用,为什么要这么定义?

    作者:元彦链接:https://www.zhihu.com/question/27602269/answer/40168594来源:知乎著作权归作者所有,转载请联系作者获得授权. 三者用途稍有不同,按 ...

  4. .NET Core 中的 Swagger 应用与微服务场景下的Swagger Api 集成显示

    Swagger 与 OpenAPI 的历史来源: Swagger 项目于 2015 年捐赠给 OpenAPI Initiative,此后被称为 OpenAPI.这两个名称可以互换使用.但是," ...

  5. 生产者-消费者问题与quene模块

    生产者-消费者问题与quene模块 下面使用线程锁以及队列来模拟一个典型的案例:生产者-消费者模型.在这个场景下,商品或服务的生产者生产商品,然后将其放到类似队列的数据结构中,生产商品的时间是不确定的 ...

  6. 图解Disruptor框架(二):核心概念

    图解Disruptor框架(二):核心概念 概述 上一个章节简单的介绍了了下Disruptor,这节就是要好好的理清楚Disruptor中的核心的概念.并且会给出个HelloWorld的小例子. 在正 ...

  7. 在laravel框架中使用mq

    本文写于2018-11-28 1.部署laravel项目 https://github.com/laravel/laravel  通过git克隆项目,或者下载zip包然后解压等方式都可以把larave ...

  8. Linux多线程实践(六)使用Posix条件变量解决生产者消费者问题

    前面的一片文章我们已经讲过使用信号量解决生产者消费者问题.那么什么情况下我们须要引入条件变量呢? 这里借用  http://www.cnblogs.com/ngnetboy/p/3521547.htm ...

  9. rabbitmq 生产者 消费者(多个线程消费同一个队列里面的任务。) 一个通用rabbitmq消费确认,快速并发运行的框架。

    rabbitmq作为消息队列可以有消息消费确认机制,之前写个基于redis的通用生产者 消费者 并发框架,redis的list结构可以简单充当消息队列,但不具备消费确认机制,随意关停程序,会丢失一部分 ...

随机推荐

  1. Python基础总结之初步认识---clsaa类(上)。第十四天开始(新手可相互督促)

    最近的类看着很疼,坚持就是胜利~~~ python中的类,什么是类?类是由属性和方法组成的.类中可能有很多属性,以及方法. 我们这样定义一个类: 前面是class关键字 后面school是一个类的名字 ...

  2. Spark 系列(七)—— 基于 ZooKeeper 搭建 Spark 高可用集群

    一.集群规划 这里搭建一个 3 节点的 Spark 集群,其中三台主机上均部署 Worker 服务.同时为了保证高可用,除了在 hadoop001 上部署主 Master 服务外,还在 hadoop0 ...

  3. CSS等分布局方法

    原文链接:http://caibaojian.com/css-equal-layout.html CSS等比例划分,在CSS布局中是比较重要的,下面分享几种常用方法和探讨一下兼容性. 一:浮动布局+百 ...

  4. JavaWeb——使用会话维持状态

    1.会话的作用 使用会话是为了维持状态,维持的是请求域请求之间的状态.因为HTTP请求自身是完全无状态的.从服务器的角度来看,当用户发出第一个请求开始,服务器无法将新的请求与之前的请求关联起来,举例说 ...

  5. JMeter定制Sampler

    1.背景 相信大家在使用JMeter工具测试的时候,经常会遇到自带采样器无法满足测试要求的情况.面对这种情况,通常的办法是使用万能的自定义Java Request的达到测试目的.这个方法有个弊端,只要 ...

  6. Django-用户-组-权限

    前言 RBAC(Role-Based Access Control,基于角色的访问控制)就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角 ...

  7. Gradle-构建生命周期

    两个重要的概念 项目 实际上,一个项目是什么取决于你要用 Gradle 做什么?项目通常代表的是构建内容. 例如在 Android 中,一个 module 就是一个项目: 项目是注册在 setting ...

  8. 「每日五分钟,玩转JVM」:线程独占区

    前言 如果我们对计算机组成有所了解,那么我们一定会知道在计算机中有一块儿特殊的区域,称之为寄存器,寄存器包括了指令寄存器和程序计数器,这两样位于CPU中,作为程序运行的大脑来控制程序的运行和流转. 而 ...

  9. 16.XML语法、CDATA、约束(DTD、Schema)讲解

    xml主要用来描述数据,比如配置文件,网络之间传输数据等,并且在android中也经常用xml来布局,,接下来便来学习xml常用的东西 1.XML语法 xml语法分为: 1.1 文档声明 必须位于文档 ...

  10. arcgis三维球中加载2000坐标系出现错误(The tiling scheme of this layer is not supported by SceneView)

    目前我们国家测绘地理信息的坐标体系基准是国家2000坐标系CGCS2000.各类地图组件如OpenLayers.Mapbox.Cesuim和ArcGIS Javascrip等都主要是支持WGS84(w ...