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

多线程共享ArrayBlockingQueue操作

阅读更多

             一直以来对Java多线程方面挺感兴趣的;在刚开始学习Java时,也只仅仅知道一些关于线程方面的基础知识,Thread t = new Thread(new RunnableImpl()); t.start(); 要么就是直接实现Runnabled接口,其实自己实现类继承Thread时,底层Thread类其实同样是实现了Runnable接口:public  class Thread implements Runnable ;

             我相信大家都会使用以上两种方式创建和启动线程,但是可能有些同学对线程的生命周期不太了解;首先提个问题,Thread().start()和Thread.run();两个方法的区别,start();方法是准备接受系统调度,一旦线程获取到CPU资源,线程立马运行起来,则此在原来主进程中又多了一个你刚刚新建的线程启动了;而run();方法则是Thread中一个普通的方法,当调用时其该run方法时,它的生命周期在当前主线程里执行,则此它的生命周期是伴随主线程的生命周期。

             当然了线程的基础知识还很多了,比如面试经常问到的Wait和Sleep区别,谈谈线程的Interrupter机制,以及Synchronized和Lock(Concurrent包下的锁),还有难点多线程编程以及性能调优等等,后续有时间我会再接下来的博客中,把自己的线程知识分享出来。第一个次在Java Eye上写博客,先前两篇算是摘要吧,往后会继续更新自己的博客。欢迎大家来拍砖,共同学习Java提高。

             啰嗦半天圆规正传,实际工作中队列算是用的比较多,有自己实现的比如LinkedList和Redis List数据结构Lpush和Rpop来实现,也有现成的比如:Concurrent包下各种队列,该包下的队列特性围绕在阻塞非阻塞以及是否双端。我个人实际工作中用到的队列,都是自己实现的如前面提到的。今天索性使用ArrayBlockingQueue写了一个Demo,主要功能是一个线程定时往队里仍数据,另一个线程消费该队列中数据,代码如下:

             

package com.test.mulit.thread;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;

public class MulitThread
{	
	//写线程池容量
	public static final Integer writerCorePoolSize = 1;
	//读线程池容量
	public static final Integer readCorePoolSize = 1;
	
	//队列大小
	public static final Integer queueSize = 5;
	
	//定义使用日志
	public static final Logger logger  = Logger.getLogger("com.test.mulit.thread.MulitThread");
	
	//读写线程共享该队列
	private static ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(queueSize, true);
	
	public static void main(String[] args)
	{	
		
		ScheduledExecutorService exec_w = Executors.newScheduledThreadPool(writerCorePoolSize);
		//满足周期性执行
		logger.info("-------------准备周期性往队列扔数字啦--------------------");
		exec_w.scheduleAtFixedRate(new WriterTask(queue), 0L, 4L, TimeUnit.SECONDS);
		
		ExecutorService exe_r = Executors.newFixedThreadPool(readCorePoolSize);
		while(true){
			logger.info("----------------开始消费队列中的数字---------------");
			//倘若队列为空则消费队列阻塞,在take()方法
			//休息2秒钟,与生产者节奏一致
			try
			{
				TimeUnit.SECONDS.sleep(1L);
			} catch (InterruptedException e)
			{
				logger.info(String.format("使用TimeUnit线程睡眠发生异常:", new Object[]{e.getLocalizedMessage()}));
				e.printStackTrace();
			}
			ReadTask readTask = new ReadTask(queue);
			exe_r.submit(readTask);
			readTask.setExec(new AtomicBoolean(true));
		}
	}
}

class WriterTask implements Runnable{
	
	private Logger logger = Logger.getLogger("com.test.mulit.thread.EriterTask");
	
	private ArrayBlockingQueue<Integer> queue_w;
	
	public WriterTask(ArrayBlockingQueue<Integer> queue){
		this.queue_w = queue;
	}
	
	@Override
	public void run()
	{	
		Random r = new Random();
		int random = r.nextInt(10000);
		boolean flage = queue_w.offer(random);
		System.out.println("队列大小:" + queue_w.size()+ " Add 返回结果:" + flage);
		logger.info(String.format("准备写入队列数字:[wwwwwwwwwwwwwwwwwwwww] %s", new Object[]{random}));
	}
}


class ReadTask implements Runnable {
	
	public static final Logger logger  = Logger.getLogger("com.test.mulit.thread.ReadTask");
		
	private ArrayBlockingQueue<Integer> queue_r;
	
	private volatile AtomicBoolean exec = new AtomicBoolean(false);
	
	public ReadTask(ArrayBlockingQueue<Integer> queue){
		this.queue_r = queue;
	}

	public AtomicBoolean getExec()
	{
		return exec;
	}

	public void setExec(AtomicBoolean exec)
	{
		this.exec = exec;
	}

	@Override
	public void run()
	{
		while(exec.get()){
			Integer result = 0;
			try
			{
				result = queue_r.take();
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
			logger.info(String.format("读取队列数字: [rrrrrrrrrrrrrrrrrrr] %s", new Object[]{result}));
		}
	}
}

 

                注意红色标注的文字,写线程和读线程的操作队列周期都刚好是2秒,控制台打印的结果如下:

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:23:47 com.test.mulit.thread.ReadTask run

信息: 读取队列数字: [rrrrrrrrrrrrrrrrrrr] 3478

2014-1-13 0:23:47 com.test.mulit.thread.WriterTask run

信息: 准备写入队列数字:[wwwwwwwwwwwwwwwwwwwww] 3478

2014-1-13 0:23:47 com.test.mulit.thread.MulitThread main

 

                当我把读线程TimeUnit.MILLISECONDS.sleep(2L);调成2微妙时,刚好和入定时入队列操作周期2秒相差1000倍,我们再看控制台打印:

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:26:54 com.test.mulit.thread.MulitThread main

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:26:54 com.test.mulit.thread.MulitThread main

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:26:54 com.test.mulit.thread.MulitThread main

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:26:54 com.test.mulit.thread.MulitThread main

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:26:54 com.test.mulit.thread.MulitThread main

信息: ----------------开始消费队列中的数字---------------

2014-1-13 0:26:54 com.test.mulit.thread.MulitThread main

......................后面还有很多,看不到消费数字打印的日志信息,很简单的印证了当Queue为空时,调用queue.take();方法会阻塞。后来我又在WriterTask类中稍作改动代码,使用queue.add(),同时队列大小我设置为5,那么按道理队列一会就会满了,引用API中的话:“将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量),在成功时返回 true,如果此队列已满,则抛出 IllegalStateException。“但是我发现后台没有抛异常,Debug发现,FutureTask里面innerRunAndReset讲该异常吃掉了。后来验证了poll() 获取并移除此队列的头,如果此队列为空,则返回 null;peek() 获取但不移除此队列的头;如果此队列为空,则返回 null;put()将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。等方法。

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    java多线程设计模式_java_设计模式_多线程_多线程课题_

    在多线程环境中,有时读操作比写操作更频繁。ReadWriteLock读写锁允许多个读线程同时访问资源,但写线程访问时会独占资源,确保数据的一致性。Java的ReentrantReadWriteLock实现了这种锁。 六、双端队列(Bounded ...

    java 多线程并发实例

    Java的BlockingQueue接口(如ArrayBlockingQueue)非常适合实现这一模型,它提供了线程安全的数据插入和移除操作。 在实例中提到的"全部开始 全部停止 单个停止"可能涉及到线程的启动和控制,这可以通过控制线程的...

    java多线程简单下载器

    如果多线程之间需要交换信息,可能使用了`BlockingQueue`,例如`ArrayBlockingQueue`,来进行数据传递。 虽然原始代码可能存在组织结构不清晰的问题,但作为学习过程的一部分,这样的项目可以帮助开发者理解如何在...

    详细剖析JAVA多线程案例教学

    由于Java程序中的多个线程共享相同的内存地址空间,因此必须谨慎处理线程间的同步问题。Java提供了多种机制来实现线程安全,包括`synchronized`关键字、`volatile`关键字以及`ReentrantLock`等高级锁机制。 #### 三...

    Java多线程设计模式_清晰完整PDF版 Java多线程设计模式源代码

    Java多线程设计模式是Java开发中的重要领域,它涉及到如何在并发环境下高效、安全地管理资源和控制程序执行流程。本资料集包含了清晰完整的PDF版书籍和源代码,为学习和理解Java多线程设计模式提供了丰富的素材。 ...

    JAVA 多线程学习笔记

    1. 同步机制:为了解决多线程并发访问共享资源导致的数据不一致问题,Java提供了synchronized关键字、Lock接口(如ReentrantLock)以及相关的并发工具类。 2. synchronized:用于修饰方法或代码块,实现互斥访问。...

    多线程通信ThreadDemo

    2. **共享资源**:在多线程环境中,多个线程可能会访问同一块内存空间,即共享资源。这可能导致数据竞争和不一致的状态,因此需要有效的通信机制来协调线程的执行顺序。 3. **线程通信方法**: - **wait() 和 ...

    JAVA多线程模式高清版+DEMO

    Java多线程是Java编程中的一个核心概念,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,实现多线程有两种主要方式:通过继承`Thread`类或者实现`Runnable`接口。这个压缩包文件"JAVA多...

    java多线程(生产者与消费者)

    这在多线程共享资源时尤为重要,防止多个线程同时操作同一资源,导致数据不一致。 2. **资源共享**:在生产者消费者模式中,数据的生产和消费都需要访问一个公共的数据结构,比如一个队列。这个队列就是共享资源,...

    java多线程设计模式详解

    在Java编程领域,多线程是提升程序性能和并发处理能力的重要手段。本文将深入探讨《java多线程设计模式详解》中所涵盖的关键知识点,旨在帮助开发者掌握多线程设计的最佳实践。 首先,我们要理解Java多线程的基础...

    JAVA多线程通信学习_服务器多线程通信_

    在服务器多线程通信中,常常需要用到阻塞队列(BlockingQueue),如ArrayBlockingQueue、LinkedBlockingQueue等。它们提供了一种线程安全的数据结构,允许生产者线程添加元素,消费者线程移除元素,而无需显式同步。...

    多线程操作

    多线程操作是计算机编程中的一个重要概念,尤其是在并发处理和优化性能方面。在现代计算机系统中,特别是多核处理器的普及,多线程已经成为提升应用程序效率的关键技术之一。标题和描述提到的应用场景是一个典型的...

    多线程设计模式

    本资料主要探讨的是如何在Java环境中利用多线程设计模式来实现资源共享,以达到高效、安全和可控的并发处理。 一、什么是多线程 多线程是指在一个进程中可以同时运行多个不同的执行流,每个执行流被称为一个线程。...

    多线程编程学习资料收集

    多线程编程是Java语言的核心特性之一,它允许开发者创建能并发执行的多个任务,从而提高了程序的执行效率和响应速度。在Java中,多线程不仅提供了并发性,还能有效地利用CPU资源,尤其在网络应用和高交互性的环境中...

    深入浅出Java多线程.pdf

    - **区别**:一个进程至少包含一个线程,而一个进程中的多个线程共享该进程的资源,如内存空间。线程切换的开销小于进程。 - **联系**:线程是进程的一部分,它们之间的关系紧密,线程的执行是在进程中进行的。 **2...

    15个多线程问题集锦

    - **定义**:原子操作是指在多线程环境下不可中断的操作。Java中的原子操作包括基本的数据类型操作、String对象的操作等。此外,Java并发库还提供了一些原子类,如`AtomicInteger`、`AtomicLong`等,用于支持原子...

    05.多线程数据保护(安全队列2

    在多线程编程中,数据保护是至关重要的一个环节,特别是在并发环境中,多个线程可能会同时访问和修改共享数据,这可能导致数据不一致、死锁等问题。本节将深入探讨如何利用安全队列来实现多线程之间的数据保护,确保...

    Java多线程 生产者-消费者模式

    生产者-消费者模式是一种经典的多线程设计模式,用于解决数据共享问题,尤其是在一个线程生产数据而另一个线程消费数据的情况下。在这个模式中,生产者负责生成数据并放入共享的数据结构(如队列),而消费者则从这...

    详细分析Java并发集合ArrayBlockingQueue的用法

    * 多线程安全:ArrayBlockingQueue使用ReentrantLock来保证多线程操作共享变量的安全问题。 * 线程等待:ArrayBlockingQueue使用Condition来控制线程等待,当队列为空或队列已满时,会让当前线程等待。 ...

    Java 多线程学习总结6

    - **可见性**:使用volatile保证多线程间共享变量的可见性。 - **有序性**:使用volatile、synchronized或java.util.concurrent包中的工具类来保证指令的执行顺序。 通过深入理解以上知识点,开发者可以更好地...

Global site tag (gtag.js) - Google Analytics