Life is too short to be little

January 6, 2012

Motto from Plato

Filed under: 人生 — James @ 10:22 am
We can easily forgive a child who is afraid of the dark; the real tragedy of life is when men are afraid of the light. 

———— Plato

January 3, 2012

Using Flash Chart 2 In Java

Filed under: Java and Programming — James @ 2:59 pm

There are several versions for Flash Chart 2 contributed by different programmers. We can just pick from one from the list:

http://teethgrinder.co.uk/open-flash-chart-2/downloads.php

To incorporate Open Flash Chart into a java project, we can simply utilize the open source project jofc2. The jar can be downloaded from google. If maven/Ivy is used, we can simple add the dependency:
        <dependency>
            <groupId>jofc2</groupId>
            <artifactId>jofc2</artifactId>
            <version>1.0.1-SNAPSHOT</version>
        </dependency> 

And we need to add the repository reference:

        <repository>
            <id>jofc2.maven.repo</id>
            <name>JOFC2 GoogleCode.com Snapshot Repository</name>
            <url>http://jofc2.googlecode.com/svn/repository/snapshots/</url&gt;
        </repository> 

jofc2 includes a lot of APIs to build different kind of Chart objects, which can be used to generate the json string for Open Flash Chart2. To embed the chart into the page, we can simply use the following javascript:

swfobject.embedSWF(
    “/pathTo/open-flash-chart.swf”,
    “chartDiv“, “chartWidth“, “chartHeight“, “9.0.0”,
    “expressInstall.swf”,
    {“data-file”:”/flash-chart/json-chart-data“}
);
<div id=”chartDiv“></div>

If your data url includes Asian characters which needs to be encoded using UTF8, there will be some problem even you change the browser settings to encoding path/parameters using utf8(Windows). The reason is that, flash viewer sdk does NOT get the settings from browsers to encoding the URLs, they get the settings from Regional Options settings in control panel(windows). There is a workaround for this, that is to repaint the chart with asynchronized javascript call:

var swf = document.getElementById(‘chartDiv‘);
swf.reload(“/flash-chart/JSON图像数据”);

This time, it will work properly as the URL is loaded with javascript which will use the browser settings.

April 4, 2011

ZT: Cassandra in 50 Words or Less

Filed under: NoSQL — James @ 11:44 am

Apache Cassandra is an open source, distributed, decentralized,  elastically scalable, highly available, fault-tolerant, tuneably consistent, column-oriented database that bases its distribution design on Amazon’s Dynamo and its data model on Google’s Bigtable. Created at Facebook, it is now used at some of the most popular sites on the Web.

[ZT:Cassandra the definitive guide]

April 3, 2011

Oracle – Steps to shrink a big tablespace(defrag)

Filed under: Java and Programming — James @ 3:06 pm

The most efficient/effective way to defrag/shrink a big tablespace in oracle is to migrate the tables/indexes to new tablespaces.

Here below are the steps:
1) Login with dba account and create new tablespaces for the database user.
Sample SQL:

create tablespace APP_TB2 datafile ‘/opt/oracle/storage/APP_TB2.dbf’ size 256m autoextend on next 128m maxsize unlimited;

2) Login with the db owner username/password

2.1) Migrate the tables

Generate the table migration script

spool /tmp/username/moveTables.sql

select
‘alter table ‘ || SEGMENT_NAME || ‘ move tablespace APP_TB2;’
FROM dba_Segments a,
dba_data_files b
WHERE b.file_id=a.relative_fno
and a.tablespace_name=‘APP_TB’ and segment_type=‘TABLE’
order by FILE_NAME,segment_name;

spool off;

2.2) Migrate the Indexes

Generate the index migration script

spool /tmp/username/MoveIndex.sql
select ‘alter index ‘ || SEGMENT_NAME || ‘ rebuild tablespace APP_TB2;’
FROM dba_Segments a,
dba_data_files b
WHERE b.file_id=a.relative_fno
and a.tablespace_name=‘APP_TB’ and segment_type=‘INDEX’
order by FILE_NAME,segment_name;
spool off;

2.3) Migrate the LOB/LOBSegments if possible

spool /tmp/username/MoveLob.sql
select ‘ALTER TABLE ‘ || table_name || ‘ move lob(‘ || COLUMN_NAME || ‘) STORE AS (TABLESPACE APP_TB2);’
from dba_tab_columns
where owner=‘APP_TB’ and data_type=‘CLOB’;
spool off;

3) check if anything missing in the original tablespace

set
lin 300
col owner format A26
col segment_name format A26
col segment_type format A26
col tablespace_name format A26
col relative_fno format 99999
col file_name format A50

SELECT owner, segment_name, segment_type,a.tablespace_name, a.relative_fno, b.file_name
FROM dba_Segments a,
dba_data_files b
WHERE b.file_id=a.relative_fno
and a.tablespace_name=‘TB_APP’
order by FILE_NAME,segment_name;

4) Never forget to change the default tablespace of the user to the new one

ALTER USER <userName> default tablespace TB_APP2;

5) change tablespace offline

alter
tablespace APP_TB offline;

Oracle – Migration From a non-partitioned table to partitioned table

Filed under: Java and Programming — James @ 2:44 pm

There are 4 kinds of partitioned tables in oracle.
http://download.oracle.com/docs/cd/B10500_01/server.920/a96524/c12parti.htm

If you see the size of your table exceeds 2G, you can consider to convert it to a partitioned table. Here below is the method to check the table size in oracle:

COLUMN TABLE_NAME FORMAT A32
COLUMN OBJECT_NAME FORMAT A32
COLUMN OWNER FORMAT A10
SELECT owner, table_name, TRUNC(sum(bytes)/1024/1024) Meg
FROM
(SELECT segment_name table_name, owner, bytes
FROM dba_segments
WHERE segment_type = ‘TABLE’
UNION ALL
SELECT i.table_name, i.owner, s.bytes
FROM dba_indexes i, dba_segments s
WHERE s.segment_name = i.index_name
AND s.owner = i.owner
AND s.segment_type = ‘INDEX’
UNION ALL
SELECT l.table_name, l.owner, s.bytes
FROM dba_lobs l, dba_segments s
WHERE s.segment_name = l.segment_name
AND s.owner = l.owner
AND s.segment_type = ‘LOBSEGMENT’
UNION ALL
SELECT l.table_name, l.owner, s.bytes
FROM dba_lobs l, dba_segments s
WHERE s.segment_name = l.index_name
AND s.owner = l.owner
AND s.segment_type = ‘LOBINDEX’)
WHERE owner in UPPER(‘&owner’)
GROUP BY table_name, owner
HAVING SUM(bytes)/1024/1024 > 10 /* Ignore really small tables */
ORDER BY SUM(bytes) desc;

Here below are the steps to convert a big table into a partitioned table:
1) create corresponding tablespaces for the partitioned table which resides in different datafiles beforehand.
2) if you have a table named “BIG_TABLE”, create a table BIG_TABLE_TMP with the simiar definition as BIG_TABLE but with a suitable partition strategy.

Sample:
CREATE TABLE BIG_TABLE_TMP
(
ID NUMBER(19) NOT NULL,
VERSION NUMBER(10),
DAY_ID VARCHAR2(255 CHAR),
PRIMARY KEY(ID)
)
PARTITION BY RANGE (DAY_ID)
(
PARTITION BIG_TABLE_20090101 VALUES LESS THAN (‘2009-01-01’) TABLESPACE BIG_TABLE_20090101,
PARTITION BIG_TABLE_MAX VALUES LESS THAN (MAXVALUE) TABLESPACE BIG_TABLE_OTHER
);
3) Migration the data
insert into BIG_TABLE_TMP select * from BIG_TABLE;
commit;
4) verify the data, check if the row count is the same
select count(1) from BIG_TABLE_TMP;
select count(1) from BIG_TABLE;
5) drop the original table
truncate table BIG_TABLE;
drop table BIG_TABLE;

6) rename the partition table
alter table BIG_TABLE_TMP rename to AD_SHOW;
6) add original constraints to the new table

7) add original indexes to the new table

8) verify the partitions
exec dbms_stats.gather_table_stats(‘&amp;owner’,‘BIG_TABLE’);
select partition_name, num_rows from user_tab_partitions where table_name = ‘BIG_TABLE’;

March 28, 2011

[ZT]谷歌跌下神坛:自大灭掉一个公司

Filed under: 计算机与 Internet — James @ 1:30 pm

(中国)计世网 (2011-03-28)

搜索引擎会让位给社交网络,但Google一定会输给Facebook吗?通过换帅,Google试图把握住自己的命运。

3月26日,拉里·佩吉(Larry Page)将迎来38岁生日。而在此一周后,这个Google的创始人之一要接替埃里克·施密特(Eric Schmidt),坐回Google的CEO之位,领导Google的产品开发和技术战略。

佩吉上一次任Google CEO的时间是十年前。现在,经历了漫长的准备期之后,施密特卸下了“成人监护者”的重担,而佩吉也结束了辅导课,准备应对Google所面临的严酷挑战。

两个月前,施密特在Google发布2010第四季度财报时,宣布了此消息。他的Twitter页面个人简介也改为:4月4日前,Google CEO;之后,前任CEO和执行董事长。

周一伦敦、周二慕尼黑、周三苏黎世、周四达沃斯……接下来的新岗位,对施密特而言也许并不轻松,他在Twitter上数着自己走向新岗位要赶的场。对佩吉而言,压力可能更大,因为互联网已经不是十年前的互联网。

三十年风水轮流转,放在互联网,轮回的时间更短。过去30年,已经有IBM、惠普、网景、微软、英特尔、雅虎、Google、苹果……先后在我们眼前闪耀过。此刻,不少人正掐着分秒计算,Facebook有效访问量全面赶超Google的时间还有多长。

Google神话

1998年,佩吉与他的同学谢尔盖·布林(Sergey Brin),在一个科技论文的数据库索引管理项目中,利用数据挖掘,开发出一个叫作BackRub的搜索引擎。一开始,他们准备将这项技术卖给网络公司。 推销不成,他们自建公司,佩吉任CEO,并将搜索引擎取名为Google。

1999年末,作为引入风险投资公司KPCB和红杉资本各1250万美元的融资的条件之一,Google得寻找一位外部人士担任CEO。他们最初的目标人选是时任苹果CEO的斯蒂芬·乔布斯,最后在2001年找来了施密特。

10年过去,Google员工从200人增加到2.44万人,收入从不足1亿美元上涨到300亿美元。尽管竞争对手不断出现,2011 年2月它的市场份额还是占到了65.6%(市场研究公司comScore的数据),是第二名雅虎的4倍多。搜索关键词、基于内容的展示广告,占到 Google收入的 96%左右。

2005年12月的《连线》(Wired)杂志上,凯文·凯勒赫(Kevin Keleher)撰文《谁在害怕Google?每一个人》。他列举了Google已经和将要涉足的领域——视频、分类广告、电信、操作系统、印刷物、电子 商务等,几乎要挑衅信息技术产业中的每一家公司。

事实如此,除了搜索和广告,Google还推出了邮箱系统Gmail(2004)、电子地图 Google Map(2005)、收购在线视频网站YouTube(2006)、手机操作系统Android(2007)、浏览器Chrome(2008)、在线免费 办公软件Docs(2009)、触摸屏手机Nexus One(2010)。当然,还有一些如Buzz、Wave等半途而废的项目,以及正在进行中的数字图书馆计划和无人驾驶汽车等等。

秉持“不作恶”原则,Google无疑是有史以来互联网企业中最具创新精神的一家,它不仅把搜索和广告做得风生水起,顺便也把原有IT 企业的业务做得更好且免费,还有诸如开源的Map帮助人们重新看世界、Android等改变了行业生态,甚至把触角伸到了和互联网相关的通信、能源领域。

2010年第四季度的财报显示,Google以25.4亿美元的净利润创下单季纪录,营业收入达到84.4亿美元,同比增26%,环比增长16%。

不过,这份财报同时还写到——“我们的业务正面临来自各方面的可怕竞争,特别是那些试图用网络信息连接用户并提供相关广告的公司。”这 些竞争者中,排在第一位的是雅虎和微软的搜索,第二位是旅游、求职、健康类垂直搜索引擎和电子商务网站,来自Facebook和Twitter等社交网站 的竞争被排到了第三位,但也许,它们才是Google最可怕的对手。

可怕的新对手

2004年8月,Google成就了迄今为止世界上最大一单互联网企业IPO,募资19.2亿美元。也是在这年2月,哈佛学生马克·扎 克伯格(Mark Zuckerberg) 在宿舍里开启了Facebook注册邀请。没有人能想到,这个出生于1984年的年轻人,6年后就有了5亿注册用户。在2011年的白宫宴会桌上,他和乔 布斯一起,分别坐在美国总统奥巴马两旁。

就像当年Google从搜索开始进入互联网,然后取代了微软的位置一样,Facebook从社交网络进入互联网,它甚至都没有去抢Google的核心业务——关键词广告(AdWords) 和面向网站的广告服务(AdSense),却很有可能不费一兵一卒打败它。

回头看互联网的发展,后来居上者,从来不是通过正面竞争从原先的第一名那里抢到位置,而是另辟蹊径,创造并满足了一种新的用户需求,建 立自己的王国。这本不是一场零和游戏,不过由于这场游戏的裁判是用户,而用户的时间和精力有限,他在哪一家停留更多时间,商业利益也会随着用户的转移而迁 徙。

此前搜索引擎领先于门户网站,因为门户向所有用户提供同样的信息,而搜索引擎则可以将用户指向他们想要了解的信息。对广告主而言,搜索广告可以把产品信息更精准地推送给客户。

现在,社交网络不仅能提供互联网上的信息,而且是用户熟人圈所关注的信息,将现实中的人际网和互联网结合起来,比搜索引擎更具交互性。而广告主的产品信息,通过圈子的力量、口碑传播得以推广,社交网络盖过搜索引擎也是情理之中。

具体来看,Google搜索是抓取全世界的信息,并通过一套算法帮助人们更便捷地找到有用的信息。Facebook和Twitter则 是让用户生产信息,并通过彼此的熟人关系来获取。而且,Facebook不对搜索引擎开放,Twitter只是部分开放,这让搜索引擎好不尴尬。

更让人无奈的是,在增强用户黏性方面,社交网站建立在开放平台之上,背后是难以计数的独立程序人员或者公司,开发出层出不穷的应用,满足用户需求。而Google则主要是靠9508名(截至2010年12月30日)工程师的生产力。

市场调研公司comScore的数据指出,2010年8月,全美互联网用户在Facebook上停留时间为4110万分钟,占到该月用户互联网停留时间的9.9%,而同期人们在Google上停留时间为3980万分钟,其中还包括YouTube。

手忙脚乱的追逐战

施密特在Google官方博客中阐述管理层变动原因称,是为了“简化管理结构、加快实施决策的步伐”。确实,他们在社交网络方面不仅后知后觉,而且手忙脚乱。

Google的三驾马车(施密特、佩吉、布林)都是计算机科学家出身,让Google带有强烈的技术色彩,哪怕是给员工提供优渥工作环 境,也是基于事实、数据和分析,得出这样更有利于提高工作效率的结果。社交网络的草根、非技术主义,和他们过往的经验是如此背道而驰,以至于Google 一直没有找到互联网和社交网的结合。

2009年5月发布的Google Wave,是Gmail和Gtalk的合体,Google本想让它作为一个开放平台,让开发者提供基于Wave的各种衍生产品,Wave还支持开放通信协 议,Google有计划让它开源成为互联网通讯平台。可惜,很多用户不知道该如何使用,反应平平,该产品在2010年底结束服务。

2010年2月推出的Google Buzz,可在Gmail邮件服务中同他人分享各类信息、自动加载好友的活动信息。但Buzz上大部分信息都是由机器自动发布的,而且常用Gmail联系 人列表会在本人不知情的情况下被公布在Buzz个人页面,这甚至让Google陷入了一场集体诉讼。

Buzz和Wave的尝试失败,一再表明Google还停留在按照技术派思路去做社交网络的事情。不过,从2010年开始,就有传闻说 Google 在开发新的社交媒体Google Me,最新消息是这一产品将在今年5月发布,而且名称改为Google Circles。这个时候再推出类似Facebook的社交媒体,听起来并不现实,在起点上至少就与之有5亿用户的距离。

移动互联网将是社交网络另一个更重要的阵地。Google在4年前就已经布局,Android操作系统占据移动互联网终端,顺势可以带动Gmail、Adsense。虽然这并不是专门针对社交网络而来,但是很有可能为Google融合社交网络开辟一新路。

2009年9月推出的定位服务Google Places,也许是Google目前产品中最容易对接社交服务的。它可以帮助商户建立自己的网页,并在网页上显示它们的位置、所处街道的景象、客户对服 务或商品的评价,商家还可以通过自己的Google Places网页打广告。再加上Google Map和Android的庞大用户数,这是定位服务(LBS)不可多得的组合。要知道,Foursquare等定位服务公司眼下正是硅谷红人,甚至被认为 是又一个Google或者Facebook的苗子。

而此时,Facebook已经将目光投向了社交网络之外,它要做邮箱,也要做搜索,大有横向发展为又一个Google之势。这就好像过去十年,Google提供互联网服务以取代桌面软件一样。在此期间,Google也许还有时间为搜索加入更多社交内容。

施密特曾在三年前接受《纽约客》采访时表示,“灭掉一个公司的,不是竞争,而是自大。我们掌握着自己的命运”。眼下掌握Google命 运的,是二次出任CEO的佩吉。《连线》杂志网站最近摘录了史蒂芬·列维(Steven Levy)即将于4月出版的《谷歌是如何思考、运转,并塑造我们的生活?》一书中部分内容,其中写到——对佩吉而言,唯一真正的失败就是没有去尝试冒险。

列维在书中认为,佩吉“与众不同,他将具有比尔·盖茨、斯蒂芬·乔布斯一样的影响力。没有人能像他那样整合谷歌的野心、道德观和世界观;与此同时,佩吉显得古怪、自大、神秘。在他的领导下,谷歌将更难预测”。

来源:南方周末

 

October 11, 2010

Load Big Excel Files In Java

Filed under: Java and Programming — James @ 5:26 pm

It is likely the customer requires the server side code to load data from excel files into databases. If the excel file size is not large, it is normally not a big problem. The developers can choose the open source projects like POI/jExcel and read the data. When the size of the file getting big, for example > 100MB, the open source projects are no more an option for java developers, as all these projects load the whole excel file into memory. Usually, the heap size required in memory is not the same as the file. It usually requires more than 10 times of that(100M excel file usually requires more than 1G memory to process).

CSV files are usually more easily to process than xls format in Java. CSV files are plain text document and can easily be processed by the java readers. Although csv files carries far more less information than excel file(for example the charts/formula… info will be lost when converting xls to csv.),  sometimes it is the only option for java developers.

Sometimes, the customer could accept to change the requirement of xls file to csv file format. But sometimes, they don’t. One important reason is that xls can have multiple sheet in one file but the csv file can have only one sheet. The system user need to use MSExcel to convert each sheet to csv one by one and upload to the server to process. This will greatly increase the work load of the system user and sometime very error prone from the user perspective.

I did some investigation and find one solution to this problem. With some coding in VBS, the conversion from excel to csv can be achieved automatically when the system is deployed in a windows environment with Excel installed.

   1: ' XLS_to_CSV_Single.vbs
   2: '
   3: ' Converts <input file> from an Excel workbook to a comma-separated text file
   4: ' and saves the results to <output file>.  Requires Microsoft Excel.
   5: '
   6: ' Usage:
   7: '  WScript XLS_to_CSV_Single.vbs <input file> <dest folder>
   8:
   9: ' WdSaveFormat constants, taken from the Word type library
  10:
  11: Const xlCSV            = 6    ' Comma-separated values
  12: Const xlUnicodeText        = 42    ' Tab delimited text file
  13:
  14: Dim xls,fos
  15:
  16: Set xls = CreateObject("Excel.Application")
  17:
  18: xls.DisplayAlerts = False
  19:
  20: inFilePath = WScript.Arguments(0)
  21: outFolder = WScript.Arguments(1)
  22:
  23: On Error Resume Next
  24:
  25: xls.Workbooks.Open inFilePath , , true
  26:
  27: If Err = 0 Then
  28:     With xls.ActiveWorkbook
  29:         Dim sheetCount
  30:         sheetCount = .Sheets.Count
  31:         For i = 1 To sheetCount
  32:             Dim sheetPath
  33:             sheetPath = GetSheetCSVNameFromPath(inFilePath,i)
  34:             sheetPath = outFolder & sheetPath
  35:             .Sheets(i).Select
  36:             .SaveAs sheetPath , xlUnicodeText
  37:         Next
  38:         .Close False
  39:     End With
  40: End If
  41:
  42: xls.Quit
  43:
  44:
  45: Function GetSheetCSVNameFromPath(xlsFilePath , sheetIdx)
  46:
  47:     Dim  idxOfPath, idxOfSuffix, fileName
  48:
  49:     idxOfPath = InStrRev(xlsFilePath, "\")
  50:     idxOfSuffix = InStrRev(xlsFilePath, ".xls")
  51:
  52:     fileName = Mid(xlsFilePath, idxOfPath + 1, idxOfSuffix - idxOfPath - 1) & ".sheet" & sheetIdx & ".csv"
  53:
  54:     GetSheetCSVNameFromPath = fileName
  55:
  56: End Function

The developer can run a system command (using the Runtime.getRuntime().exec(…) method) in windows to complete the conversion to extract all the sheets within one excel file to a destination folder and then process the output csv files one by one (WScript XLS_to_CSV_Single.vbs <input file> <dest folder>). With this approach, the system could then reduce the memory requirement to a very low level. After all, excel file format is private to Microsoft and the best tool to process xls format is MSExcel.

This solution has some portability issues when the system is deployed in a linux/Unix system. I am not sure if the OpenOffice(can be run in linux and unix) support similar functionalities like VBA script to do the conversion. If so, that will be great. The portable code could be implemented in these systems.

 

Hello world!

Filed under: Uncategorized — James @ 9:34 am

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!

June 28, 2010

Trunk Test For Web Navigation

Filed under: Usability — James @ 9:02 pm

Imagine that you’ve been blindfolded and locked in the trunk of a car, then driven around for a while and dumped on a page somewhere deep in the bowels of a Web site. If the page is well designed, when your vision clears you should be able to answer these questions without hesitation:

  • What site is this? (Site ID)
  • What page am I on? (Page name)
  • What are the major sections of this site? (Sections)
  • What are my options at this level? (Local navigation)
  • Where am I in the scheme of things? (“You are here” indicators)
  • How can I search?

Here’s how you perform the trunk test:
    Step 1 Choose a page anywhere in the site at random, and print it.
    Step 2 Hold it at arm’s length or squint so you can’t really study it closely.
    Step 3 As quickly as possible, try to find and circle each item in the list below.(You won’t find all of the items on every page.)
        Circle:
            1. Site ID
            2. Page name
            3. Sections and subsections
            4. Local navigation
            5. “You are here” indicator(s)
            6. Search

April 14, 2010

BlockingThreadPoolExecutor

Filed under: Java and Programming — James @ 4:20 pm

With the java.util.concurrent.ThreadPoolExecutor class, we can usually implement easy asynchronized job runners. When I was using it to implement some web crawling tools, I found the following problems:

  • The constructor of the ThreadPoolExecutor allows you to pass in a BlocingQueue<Runnable> to preserve the waiting requests.
    • If the user passed  unbounded queue, and if the Task consumer is not running very fast and the queue would be very long. This would possibly exhaust a great deal of memory and even more cause an OutOfMemory error.
    • If the user passed in a bounded queue, after the queue is full, the execute(…) method will simply reject the coming request and delegate the failed request to its RejectedExecutionHandler. Of course the user could execute the original task again in the handler callback, but this usually leads to a non efficient busy-waiting approach.

This problem will affect the implementation of a web crawler. In a typical crawling tool, we usually have two different of roles: Analyzer and Crawler. The Analyzer is usually responsible to parse the crawled web page and it usually spawn several more sub Analyzer/Crawler tasks. From implementation perspective, this means, in the Analyzer would usually call the execute(…) method internally to submit new tasks which cause a rapidly size-increased waiting queue.

The idea to solve this problem is to guard the ThreadPoolExecutor with some locks to block it submit more tasks. I come up with the implementation of BlockingThreadPoolExecutor.

   1: import java.util.concurrent.LinkedBlockingQueue;
   2: import java.util.concurrent.ThreadPoolExecutor;
   3: import java.util.concurrent.TimeUnit;
   4: import java.util.concurrent.locks.Condition;
   5: import java.util.concurrent.locks.Lock;
   6: import java.util.concurrent.locks.ReentrantLock;
   7:  
   8: /**
   9:  * @author James Zheng
  10:  */
  11: public class BlockingThreadPoolExecutor {
  12:  
  13:     private int taskCount = 0;
  14:  
  15:     private final int maxProcessingCount;
  16:  
  17:     private Lock lock = new ReentrantLock();
  18:  
  19:     private Condition notFullCondition = lock.newCondition();
  20:  
  21:     private Condition emptyCondition = lock.newCondition();
  22:  
  23:     private ThreadPoolExecutor executor;
  24:  
  25:     public BlockingThreadPoolExecutor(final int threadCount) {
  26:         this(threadCount, 0);
  27:     }
  28:  
  29:     public BlockingThreadPoolExecutor(final int threadCount, final int maxWaitingTaskCount) {
  30:         if (threadCount <= 0) {
  31:             throw new IllegalArgumentException(
  32:                     "threadCount should be a positive integer:" + threadCount);
  33:         }
  34:         if (maxWaitingTaskCount < 0) {
  35:             throw new IllegalArgumentException("maxWaitingTaskCount should be >= 0:"
  36:                     + maxWaitingTaskCount);
  37:         }
  38:         this.maxProcessingCount = maxWaitingTaskCount + threadCount;
  39:         executor = new ThreadPoolExecutor(threadCount, threadCount, 0, TimeUnit.SECONDS,
  40:                 new LinkedBlockingQueue<Runnable>()) {
  41:             @Override
  42:             protected void afterExecute(Runnable r, Throwable t) {
  43:                 super.afterExecute(r, t);
  44:                 lock.lock();
  45:                 try {
  46:                     taskCount--;
  47:                     notFullCondition.signal();
  48:                     if (taskCount == 0) {
  49:                         emptyCondition.signal();
  50:                     }
  51:                 } finally {
  52:                     lock.unlock();
  53:                 }
  54:             }
  55:         };
  56:     }
  57:  
  58:     public void submit(Runnable task) {
  59:         lock.lock();
  60:         try {
  61:             while (taskCount == maxProcessingCount) {
  62:                 notFullCondition.awaitUninterruptibly();
  63:             }
  64:             taskCount++;
  65:             executor.submit(task);
  66:         } finally {
  67:             lock.unlock();
  68:         }
  69:     }
  70:  
  71:     public void awaitAndTerminate() throws InterruptedException {
  72:         lock.lock();
  73:         try {
  74:             while (taskCount != 0) {
  75:                 emptyCondition.await();
  76:             }
  77:             executor.shutdown();
  78:         } finally {
  79:             lock.unlock();
  80:         }
  81:     }
  82: }
Older Posts »

Create a free website or blog at WordPress.com.