[Java] Java 多线程案例分析

标签: java java 多线程 | 发表时间:2017-03-19 10:48 | 作者:xsank
出处:https://www.v2ex.com/

开题

设定有如下需求:
现要从 hbase中导出 2016 年整年的,大约 10w只股票行情数据,数据总量约 100t
导出成如下格式:

  2016-01-01/facebook.txt linkedin.txt amazon.txt google.txt...
...
2016-12-31/facebook.txt linkedin.txt amazon.txt google.txt...

汇总到 hdfs中供需求方使用

分析

已知数据量规模大概是 100t,那么单台机器处理肯定不是不行的,先不说大多数磁盘都没这么大,即便磁盘有这么大,单台机器处理对于内存和 cpu 要求也很高,所以我们将问题一般化,使用数量有限的低配机器。
那么接下来要处理的就是如何对任务进行分割,最容易想到的有两种:

  1. 按照时间分割
    2016 年共 365 天,那么最多拆分成 365 组,粒度足够细。再按照小时拆分又涉及到数据合并,先不考虑。
  2. 按照股票分割
    一共 10w 只,粒度可以拆分的更细。

以上两种都可以,都涉及到最后汇总 hdfs 的情况,不过按照股票分割粒度更细,更便于控制,这里我们选用后者。

选定分割方式后又会遇到一个问题,如果将任务分割给多台机器,这里先说两种:

  1. 按照机器数平均分配
    事先将股票裁剪分配好到一台中心机器上,每台机器设定只读取其中一部分或者直接将裁剪好的股票信息分配到对应的机器 这种做否有两个缺点:
  1. 这会导致机器状态相关,不便于横向扩展
  2. 任务平均分配可能存在不均,资源利用率不够
  1. 由机器实际处理能力决定
    事先将股票信息保存在一台中心机器上,每台机器从这里统一消费

很明显方案二比方案一要好,这里我们选用方案二

现在机器已经分配好了,剩下的就只有单机处理了,剩下的就只有并发的知识了
应到每台机器上的逻辑就是:对于获取到的每只股票,扫描整年的数据,然后写本地,写好之后 copy 到 hdfs 即可,再细化下去后大概会遇到如下几个问题:

  1. 需要添加生产者-消费者模型
    获取股票后要扫取一天的数据,生产者及是 hbase数据读取方,消费者便是数据处理方
  2. 本地磁盘大小有限,数据要及时清理
    假设我们的机器磁盘都只有 100g的空间,那么必须考虑本次可存的文件最大上线,一旦告警必须等待磁盘数据拷贝完成再继续处理
  3. 保证数据完整性
    这里的任何一条数据都是不能丢弃的,你可以 block任务,但是不能 reject
  4. 扫取范围
    对于这种类 TSDB的存储,当然最好只扫描一次,但是扫出来的数据都必须根据时间判断,会浪费性能,多线程写还需要考虑文件锁,进一步降低性能,另外如果程序判断按照天截止,又容易造成数据遗漏,不按照天截止缓存整年的数据之后再拷贝到 hdfs又会增加时间开销
    所以这里最好按照天的粒度再分区间 scan,每个线程仅控制一天,避免多线程写,同时便于单文件写好之后立即通知上传线程将文件汇总过去

知识点

第三方系统的掌握

如已经明确相关的 hbasehdfs,其他包含可能会用到的组件如:消息队列,缓存等

多线程控制

会涉及到 BlockingQueue, ThreadPool, CountdownLatch, Lockconcurrent知识运用,举个具体例子:

  1. 等待 ThreadPool的所有任务完成
  1. invokeAll 的使用
  2. shutdown 结合 awaitTermination 的使用
  1. ThreadPool提交任务阻塞
  1. 定制 BlockingQueue
  1. Thread同步控制
  1. CountdownLatch的使用
  1. 控制生产者和消费者终止
  1. PoisonPill的使用
  1. 异步任务处理
  1. 小心阻塞操作,避免挂起
  1. Lock使用
  1. 根据并发冲突的实际情况,控制锁粒度

总结

这就是一种比较常见的,用到“大数据”处理和并发知识的场景,如果网友有更好的思路,欢迎留言讨论~

相关 [java java 多线程] 推荐:

Java Thread多线程

- - CSDN博客推荐文章
Java Thread多线程. Java 多线程例子1 小例子. super("zhuyong");//设置线程的名字,默认为“TestThread”. Java 多线程例子2 前台线程(用户线程) 后台线程(守护线程 ). 1,setDaemon(true)后就是后台线程(守护线程 ),反之就是前台线程(用户线程).

[Java] Java 多线程案例分析

- - V2EX
现要从 hbase中导出 2016 年整年的,大约 10w只股票行情数据,数据总量约 100t. 汇总到 hdfs中供需求方使用. 已知数据量规模大概是 100t,那么单台机器处理肯定不是不行的,先不说大多数磁盘都没这么大,即便磁盘有这么大,单台机器处理对于内存和 cpu 要求也很高,所以我们将问题一般化,使用数量有限的低配机器.

Java多线程之synchronized

- - CSDN博客推荐文章
这里通过三个测试类阐述了synchronized应用的不同场景. 首先是最基本的synchronized Method的使用.  * @see 概述:Java中的每个对象都有一个锁(lock)或者叫做监视器(monitor) .  * @see 说明:当synchronized关键字修饰一个方法时,则该方法为同步方法 .

java多线程总结

- - Java - 编程语言 - ITeye博客
在java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口. 对于直接继承Thread的类来说,代码大致框架是:. class 类名 extends Thread{. * @author Rollen-Holt 继承Thread类,直接调用run方法.             System.out.println(name + "运行     " + i);.

Java多线程(二)同步

- - CSDN博客编程语言推荐文章
如果你的java基础较弱,或者不大了解java多线程请先看这篇文章 java多线程(一)线程定义、状态和属性. 同步一直是java多线程的难点,在我们做android开发时也很少应用,但这并不是我们不熟悉同步的理由. 希望这篇文章能使更多的人能够了解并且应用java的同步. 在多线程的应用中,两个或者两个以上的线程需要共享对同一个数据的存取.

Java多线程学习

- - CSDN博客编程语言推荐文章
  线程是一种轻量级的进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单. 即多个线程可以同时执行,就像有多条流水线一样,可以同时进行工作,是并发执行的.   程序是由进程组成的,进程是由线程组成的.

java多线程设计wait/notify机制

- - CSDN博客推荐文章
  当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait() , 放弃对象锁..   之后在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:.   # 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内.

Java多线程之wait()和notify()

- - CSDN博客推荐文章
直接看测试代码吧,细节之处,详见注释.  * Java多线程之wait()和notify()的妙用 .  * @see 问题:同时启动两个线程和同时启动四个线程,控制台打印结果是不同的 .  * @see      同时启动两个线程时,控制台会很规律的输出1010101010101010 .  * @see      同时启动四个线程时,控制台起初会规律的输出10101010,一旦某一刻输出一个负数,那么后面的输出就会"一错再错" .

Java 多线程内存模型

- - ITeye博客
Java 多线程内存模型.       Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果. 在此之前,主流程序怨言(如C/C++等)直接使用物理硬件(或者说操作系统的内存模型),因此,会由于不同的平台上内存模型差异,导致程序在一套平台上并发完成正常,而在另一套平台上并发访问却经常出错,因此经常需要针对不同的平台来编写程序.

Java多线程程序的测试

- - 四火的唠叨
这个问题最初来自于一封公司内部的话题探讨邮件,再加上了一些我的理解. 首先,需要明确的是,用Java通常构建多线程安全的程序“非常”困难,如果还没有体会到“非常”的话,阅读《Java Concurrency in Practice》(中文名叫做《Java并发编程实战》,在我的 书单里面,我认为它基本是最好的系统介绍Java并发的书了)可能可以改变你的看法.