一直以来对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()将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。等方法。
”
相关推荐
ArrayBlockingQueue源码分析.docx
【2018最新最详细】并发多线程教程,课程结构如下 1.并发编程的优缺点 2.线程的状态转换以及基本操作 3.java内存模型以及happens-before规则 4.彻底理解synchronized 5.彻底理解volatile 6.你以为你真的了解final吗...
模拟实现3个用户对统一账号进行存入、取出、转账等操作CustomerGenerator线程:随机生成办理业务的顾客以及其操作类型、金额等 Cashier线程:从等待队列中抽取第一个顾客并为其办理业务多线程:ArrayBlockingQueue&...
JAVA线程基本学习, JAVA多线程的特性= 线程池: 本质上是一个对象池, 用来管理线程资源. 在任务执行前, 需要从线程池中拿出线程来执行. 在任务执行完成之后, 需要把线程放回线程池. 线程池好处: 降低资源的消耗...
ArrayBlockingQueue源码解析__动力节点共23页.pdf.zip
ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列。下面通过本文给大家介绍Java concurrency集合之ArrayBlockingQueue的相关知识,感兴趣的朋友一起看看吧
并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解
主要介绍了详细分析Java并发集合ArrayBlockingQueue的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要介绍了java并发之ArrayBlockingQueue详细介绍的相关资料,需要的朋友可以参考下
在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的... 使用ArrayBlockingQueue的一个子类BlockingQueue实现一个可阻塞队列,一个线程put另一个线程take,当队列为空时take等待,当线程满时put等待
今天小编就为大家分享一篇关于Java源码解析阻塞队列ArrayBlockingQueue常用方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
主要介绍了java中LinkedBlockingQueue与ArrayBlockingQueue的异同,需要的朋友可以参考下
ArrayBlockingQueue是一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素
今天小编就为大家分享一篇关于Java源码解析阻塞队列ArrayBlockingQueue介绍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
今天小编就为大家分享一篇关于Java源码解析阻塞队列ArrayBlockingQueue功能简介,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
Java并发编程学习宝典(漫画版),Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习宝典(漫画版)Java并发编程学习...
} } 数据处理:这⾥的思路也是将数据⼩化然后处理,这⾥使⽤了多线程,设定单个线程处理量,然后开启多个线程处理,这⾥需要考虑你的服 务器的承载能⼒,如果线程开得太多了,处理不过来,会出现蹦死的情况。...