Java多线程开发之~~~多条件Condition接口的使用

我们在多线程开发中,可能会出现这种情况。就是一个线程需要另外一个线程满足某某条件才能继续运行,或者需

要其他线程满足好几个条件才能运行,对于这样的多条件的多线程并发,我们如何控制好各个线程之间的关系,使他们

能很好的处理冲突不至于相互出现问题呢,下面我们来介绍一下Java提供的Condition这个接口,这个接口很好的实现了

这种需求。

对于这个问题最经典的例子就是生产者消费者模型,生产者当缓冲区满的时候不生产商品知道缓冲区有空余,消费

者当缓冲区为0 的时候不拿商品,直到生产者向缓冲区放入商品,下面我们使用Conditon这个接口来实现这样的需求。

package com.bird.concursey.charpet4;

/**
 * First, let's implement a class that will simulate a text file. Create a class named
FileMock with two attributes: a String array named content and int named
index. They will store the content of the file and the line of the simulated file that will
be retrieved.
 * @author bird
 * 2014年9月21日 下午6:55:31
 */
public class FileMock {

	private String content[];
	private int index;

	/**
	 * Implement the constructor of the class that initializes the content of the file with
random characters.
	 * @param size
	 * @param length
	 */
	public FileMock(int size, int length) {
		content = new String[size];
		for(int i = 0; i < size; i++) {
			StringBuilder buffer = new StringBuilder(length);
			for(int j = 0; j < length; j++) {
				int indice = (int) (Math.random() * 255);
				buffer.append((char)indice);
			}
			content[i] = buffer.toString();
		}
		index = 0;
	}

	/**
	 * Implement the method hasMoreLines() that returns true if the file has more lines
to process or false if we have achieved the end of the simulated file.
	 * @return
	 */
	public boolean hasMoreLines() {
		return index < content.length;
	}

	/**
	 * Implement the method getLine() that returns the line determined by the index
attribute and increases its value.
	 * @return
	 */
	public String getLine() {
		if(this.hasMoreLines()) {
			System.out.println("Mock: " + (content.length - index));
			return content[index++];
		}
		return null;
	}
}
package com.bird.concursey.charpet4;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * implement a class named Buffer that will implement the buffer shared by
 * producers and consumers.
 *
 * @author bird 2014年9月21日 下午6:58:13
 */
public class Buffer {

	private LinkedList<String> buffer;
	private int maxSize;
	private ReentrantLock lock;
	private Condition lines;
	private Condition space;
	private boolean pendingLines;

	/**
	 * Implement the constructor of the class. It initializes all the attributes
described previously.
	 * @param maxSize
	 */
	public Buffer(int maxSize) {
		this.maxSize = maxSize;
		buffer = new LinkedList<String>();
		lock = new ReentrantLock();
		lines = lock.newCondition();
		space = lock.newCondition();
		pendingLines = true;
	}

	/**
	 * Implement the insert() method. It receives String as a parameter and tries
to store it in the buffer. First, it gets the control of the lock. When it has it, it then
checks if there is empty space in the buffer. If the buffer is full, it calls the await()
method in the space condition to wait for free space. The thread will be woken up
when another thread calls the signal() or signalAll() method in the space
Condition. When that happens, the thread stores the line in the buffer and calls
the signallAll() method over the lines condition. As we'll see in a moment, this
condition will wake up all the threads that were waiting for lines in the buffer.
	 * @param line
	 */
	public void insert(String line) {
		lock.lock();
		try {
			while(buffer.size() == maxSize) {
				space.await();
			}
			buffer.add(line);
			System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread().getName(),buffer.size());
			lines.signalAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}

	/**
	 * Implement the get() method. It returns the first string stored in the buffer. First, it
gets the control of the lock. When it has it, it checks if there are lines in the buffer.
If the buffer is empty, it calls the await() method in the lines condition to wait
for lines in the buffer. This thread will be woken up when another thread calls the
signal() or signalAll() method in the lines condition. When it happens, the
method gets the first line in the buffer, calls the signalAll() method over the
space condition and returns String.
	 * @return
	 */
	public String get() {
		String line = null;
		lock.lock();
		try {
			while((buffer.size() == 0) && (hasPendingLines())) {
				lines.await();
			}
			if(hasPendingLines()) {
				line = buffer.poll();
				System.out.printf("%s: Line Readed: %d\n",Thread.currentThread().getName(),buffer.size());
				space.signalAll();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
		return line;
	}

	/**
	 * Implement the setPendingLines() method that establishes the value of the
attribute pendingLines. It will be called by the producer when it has no more lines
to produce.
	 * @param pendingLines
	 */
	public void setPendingLines(boolean pendingLines) {
		this.pendingLines=pendingLines;
	}

	/**
	 * Implement the hasPendingLines() method. It returns true if there are more lines
to be processed, or false otherwise.
	 * @return
	 */
	public boolean hasPendingLines() {
		return pendingLines || buffer.size() > 0;
	}
}
package com.bird.concursey.charpet4;

public class Producer implements Runnable {

	private FileMock mock;

	private Buffer buffer;

	public Producer(FileMock mock, Buffer buffer) {
		this.mock = mock;
		this.buffer = buffer;
	}

	/**
	 * Implement the run() method that reads all the lines created in the FileMock
object and uses the insert() method to store them in the buffer. Once it finishes,
use the setPendingLines() method to alert the buffer that it's not going to
generate more lines.
	 */
	@Override
	public void run() {
		buffer.setPendingLines(true);
		while(mock.hasMoreLines()) {
			String line = mock.getLine();
			buffer.insert(line);
		}
		buffer.setPendingLines(false);
	}

}
package com.bird.concursey.charpet4;

import java.util.Random;

public class Consumer implements Runnable {

	private Buffer buffer;

	public Consumer(Buffer buffer) {
		this.buffer = buffer;
	}

	/**
	 * Implement the run() method. While the buffer has pending lines, it tries to get one
and process it.
	 */
	@Override
	public void run() {
		while(buffer.hasPendingLines()) {
			String line = buffer.get();
			processLine(line);
		}
	}

	/**
	 * Implement the auxiliary method processLine(). It only sleeps for 10 milliseconds
to simulate some kind of processing with the line.
	 * @param line
	 */
	private void processLine(String line) {
		Random random = new Random();
		try {
			Thread.sleep(random.nextInt(100));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		FileMock fileMock = new FileMock(100, 10);
		Buffer buffer = new Buffer(20);

		Producer producer = new Producer(fileMock, buffer);
		Thread threadProducer = new Thread(producer, "Producer");

		Consumer consumers[] = new Consumer[3];
		Thread threadConsumers[] = new Thread[3];
		for(int i = 0; i < 3; i++) {
			consumers[i] = new Consumer(buffer);
			threadConsumers[i] = new Thread(consumers[i], "consumer " + i);
		}

		threadProducer.start();
		for(int i = 0; i < 3; i++) {
			threadConsumers[i].start();
		}
	}

}

注意:

When a thread calls the await() method of a condition, it automatically frees the control of the lock, so that another thread can get it and begin the execution of the same, or another critical section protected by that lock.

时间: 2024-10-06 17:47:31

Java多线程开发之~~~多条件Condition接口的使用的相关文章

Java之多线程开发时多条件Condition接口的使用

转:http://blog.csdn.net/a352193394/article/details/39454157 我们在多线程开发中,可能会出现这种情况.就是一个线程需要另外一个线程满足某某条件才能继续运行,或者需 要其他线程满足好几个条件才能运行,对于这样的多条件的多线程并发,我们如何控制好各个线程之间的关系,使他们 能很好的处理冲突不至于相互出现问题呢,下面我们来介绍一下Java提供的Condition这个接口,这个接口很好的实现了 这种需求. 对于这个问题最经典的例子就是生产者消费者模

Java多线程开发技巧

很多开发者谈到Java多线程开发,仅仅停留在new Thread(...).start()或直接使用Executor框架这个层面,对于线程的管理和控制却不够深入,通过读<Java并发编程实践>了解到了很多不为我知但又非常重要的细节,今日整理如下. 不应用线程池的缺点 有些开发者图省事,遇到需要多线程处理的地方,直接new Thread(...).start(),对于一般场景是没问题的,但如果是在并发请求很高的情况下,就会有些隐患: 新建线程的开销.线程虽然比进程要轻量许多,但对于JVM来说,新

Java多线程开发系列之四:玩转多线程(线程的控制2)

在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接进入正题:  3.线程睡眠  sleep() 所有介绍多线程开发的学习案例中,基本都有用到这个方法,这个方法的意思就是睡眠(是真的,请相信我...).好吧,如果你觉得不够具体,可以认为是让当前线程暂停一下,当前线程随之进入阻塞状态,当睡眠时间结束后,当前线程重新进入就绪状态,开始新一轮的抢占计划!

java多线程(一)Race Condition现象及产生的原因

转载请注明出处http://blog.csdn.net/xingjiarong/article/details/47603813 什么是Race Condition 首先,什么是Race Condition呢,Race Condition中文翻译是竞争条件,是指多个进程或者线程并发访问和操作同一数据且执行结果与访问发生的特定顺序有关的现象.换句话说,就是线程或进程之间访问数据的先后顺序决定了数据修改的结果,这种现象在多线程编程中是经常见到的. Race Condition 实例 class My

Java 多线程之 Thread 类 和 Runnable 接口初步使用

Thread 类 Thread 类是在 JDK1.0 时就存在的, 在 Java 中接触的多线程开发基本上都会从这个类开始. Thread之定义线程类 使用 Thread 创建线程的方法很简单, Thread 是一个类, 在需要创建线程时, 我们只需要继承这个类, 并将 run() 方法进行重写即可. class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = min

Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread

事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一.事件派发线程的前世今生 事件(Event)派发(Dispatch)线程(Thread)简写为EDT,也就是各个首字母的简写.在一些书或者博客里边也将其译为事件分发线程.事件调度线程.巴拉巴拉,总之,知道这些名字就行.笔者认为这里翻译成派发更准确点. 熟悉Swing和awt编程的小伙伴对事件派发线程

Java多线程开发系列之一:走进多线程

对编程语言的基础知识:分支.选择.循环.面向对象等基本概念后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介绍 多线程开发的概念.使用.线程状态.同步.线程池.希望与大家共勉. 在第一部分,也就是本节我们先介绍下 什么是多线程程序.线程和进程又是什么,以及为什么要搞多线程. (一)什么是多线程程序 多线程听上去是非常专业的概念,其实非常简单,我们在日常生活中,经常的接触到多线程. 比如 (1)在工厂,工人努力

Java多线程中的竞争条件、锁以及同步的概念

竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生"竞争条件"的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作是非"原子化"的,可能前一个线程对数据的操作还没有结束,后一个线程又开始对同样的数据开始进行操作,这就可能会造成数据结果的变化未知. package com.huojg.test; public class TestThread { public static void

java多线程开发,Executors、FutureTask、Callable

java多线程如何应用呢,几乎学java的同学都知道Thread类和Runable接口.继承Thread类或者实现Runable接口,调用thread的start方法即可启动线程. 然后是线程池,就是启动一系列的线程,当需要启动某个线程时,从线程池中拿取一个线程. 最近使用到需要启动一个线程进行复杂运算并且得到其返回值. 就用到Callable. public interface Callable<V> { /** * Computes a result, or throws an excep