china-pub購書網址:http://www.china-pub.com/computers/common/info.asp?id=34017
1、總體感受
a) 這本書主要介紹的是intel平臺下的多核程序設計技術,Windows介紹較多,Linux介紹較少,Java更少。作者是Intel公司的平臺架構師,我們知道wintel聯盟,書中的內容如此分布也是正常。
b) 此書讓我懂得了很多硬件方面的并行知識。
c)
此書介紹Windows API中和并發相關的部分,很詳盡,比Jeffrey
Richter的《Windows核心編成》有深度多了,也精辟多了。顯然《多核程序設計》作者屬于有經驗的工程師,Jeffrey
Richter只是一個寫手,兩者沒有可比性。不過這方面的知識偶早已涉獵,當作復習一遍罷了。
d) 此書偏向底層,硬件和操作系統層面。更高層面的技術介紹較少。
e) 第一次了解OpenMP技術的一些細節。以前只聽說,也沒查過任何相關資料,在此書中看到了相關部分,挺有意思的,感覺那些語法很有趣。Herb Sutter也是要在語法方面動手。反正我在有了一個粗淺認識之后,覺得很有意思。
-------------------------
2、并發流程控制
Fence
在Java
中對應的是java.util.concurrent.CountDownLatch。最初接觸CountDownLatch的時候,由于其實現很簡單,
當時覺得是一個可有可無的工具類。但后來在不同的場景多次使用,發現很有用。在此書中再次發現類似的Fence,用于在共享存儲多處理器或者多核環境中,
確保存儲操作的一致性。我猜這屬于業界并發流控制的典型手段了。
Barrier
在Java中對應的是java.util.concurrent.CyclicBarrier。在應用程序中,一個場景就是和定時器結合使用,countDown、await、reset,做定時定量批量處理。
我猜這也屬于業界并發流程控制的典型手段了。
(CountDownLatch和CycliBarrier的實現代碼都很簡單,但很有用,他們都屬于并發流程控制的典型手段)
-------------------------
3、非阻塞算法
InterLocked在Java中對應的是java.util.concurrent.atomic.xxx
書中提到了cache行乒乓球現象導致的性能問題,提高了非阻塞算法的復雜性問題。
關于性能問題,developerworks上有一片文章,有測試數據:
《Java 理論與實踐: 流行的原子》 (http://www.ibm.com/developerworks/cn/java/j-jtp11234/index.html)
文章中的測試數據表明,直接使用atomic在1個和2個處理器時是最好的,4個處理器以上,使用java.util.concurrent.locks.ReentrantLock性能更好。
java.util.concurrent包,提供了很多高級的概念,隱藏了非阻塞算法帶來的復雜度,其底層框架達到了最佳性能。
-------------------------
4、任務分解、數據分解以及數據流分解
此書中明確提出了這三個概念,很有用,讓我在這方面的知識概念清晰化了。
任務分解
Java
中的Executor,提供了任務分解的手段和模式。任務分解提交給Executor執行。java.util.concurrent中提供了
Future,用于任務提交者和Executor之間的協調。Future是一種很好的手段,在很多涉及并發的庫都提供。例如C++網絡并發庫中提供了
Future,Herb Sutter要在Visual C++中引入Future。
數據分解
數據分解的手段很多也很常見。
Java中,提供了一種高級的數據分解協同模式java.util.concurrent.Exchanger這個類。早在Java SE
5.0時,Exchanger只支持2Parties,Java SE 6.0支持n
parties。偶想象過一些很酷的應用場景,寫過模擬測試,但一直沒有機會用于實際開發中。
數據流分解
書中提到了眾多周知的producer/consumer問題。
其實java.util.concurrent.Exchanger類,既有數據分解,又有數據流分解,exchanger中的producer和consumer的角色會互換的,很有意思。
-------------------------
5、作為Java程序員的思考
Java SE 5.0之后,提供了util.concurrent包,功能齊全,性能卓越,非常優秀。從此書來看,業界流行的流程控制手段和并發程序設計方法一個不落。我們應該感謝偉大的Doug Lea,他為我們帶了一個如此完美的并發庫!
一旦方案想清楚,剩余部分的工作效率瓶頸就在于你的手速了。最近一直看起點中文網上的《師士傳說》,主角葉重一個強項就是手速。
最基本的就是盲打。不會盲打的通常屬于“編碼低能兒”。身邊也有不會盲打的朋友,他們通常都有一個問題,就是眼高手低,說說還行,動手就不行。當然他們能夠在IT研發領域還混得很好,是因為在其他方面擁有優秀的能力。
熟練掌握快捷鍵是關鍵。鍵盤和鼠標之間通常有較大的距離,手經常在鍵盤和鼠標之間移動,會降低效率,也容易導致疲勞,用鼠標過多,也容易導致齷齪的鼠標手。解決這個問題的辦法,就是純鍵盤操作,其實很多IDE的快捷鍵功能強大,足以讓你純鍵盤操作,高效率編碼。
我比較熟悉的IDE是Eclipse,就以Eclispse來說吧。
Eclipse的keys列表中,屬于Eclipse本身有180多個快捷鍵,要提高編碼速度,就應該熟練使用其中絕大多數。
練習的辦法:
1、在Windows/Preferences/General/keys中,使用Export,把快捷鍵導出,導出的格式是csv格式,Windows下可以用Excel直接打開,Linux下可以用OpenOffice打開,打開時選擇分隔符為“,”。
2、挨個練習使用。每天練習一部分,反復練習,堅持一段時間。
3、開始的時候,把鼠標放到一個不方便使用的角落,盡量不要讓自己用鼠標。
4、快捷鍵的組合使用需要加強訓練。在不同場景下,認真考慮用怎樣的組合快捷鍵最高效。
如此堅持一段時間之后,編碼的過程會很流暢,速度就會大大提高。
這是一個很老的問題了,經常在論壇上看到,很多人也寫了相關的文章。我在這方面擁有較多的經驗,我也談一下我的看法吧。
我曾經實現過金蝶EAS BOS的多數據支持引擎,腳本引擎,也作過O-R Mapping的預研工作,曾經對多個O-R Mapping產品做過研究。
C++、Java、C#都源自Algol,這系列語言也稱為Imperative語言,中文翻譯為命令式語言。命令式語言建立在馮*諾依曼體系結構上,程序員必須處理變量管理、變量復制。這樣的結果是增加了執行的效率,但帶來了程序開發的艱苦。
LISP、Schema、Haskell等語言屬于函數式語言,函數式語言基于數學函數,不使用變量或者賦值語句產生結果,使用函數的應用、條件表示和遞歸作為執行控制。函數式語言是更高級的程序設計語言,和命令式語言相比,編寫更少的代碼,更高的開發效率,這是函數式語言的明確有點。很多編程技術都首先應用于函數式語言,例如范型、垃圾收集等。很多函數式語言都增加了一些命令式語言的特征,增加效率和易用性。
SQL語言是一個領域專用語言,專門用于處理關系數據。他具備一些函數式語言的特征,在處理關系數據方面非常直觀和簡介。在處理選擇、投影、聚合、排序等等操作方面,顯然比在Java或者C#中要方便得多。SQL也是易學易用。很多非程序員都掌握SQL,在金蝶,大多需求人員都熟練掌握SQL。SQL的解釋需要損耗一定的性能,在對性能極端要求的情況下,通常不使用關系數據庫。例如Google Account采用Berkeley DB等。
現在關系數據庫已經發展很成熟,數據庫的一些技術發展得很好,包括事務等,其中一些從數據庫中發展起來的技術,還應用到操作系統中了。在前些年面向對象技術狂熱的時候,作了很多面向對象數據庫的研究,但是都沒有取得較大的成功。在主流的關系數據庫中,大多都包括了面向對象的支持,例如Oracle、Sybase,都具備了很豐富的面向對象功能,但是很少任用。
現在有人跟我說起db4o這樣的數據庫,我認為db4o不會取得成功,因為他在錯誤的方向發展。
現在關系數據庫最流行,最流行的應用開發語言包括Java、C#等,都是面向對象命令式語言。開發語言需要訪問關系數據庫,需要轉換,轉換的過程比較繁瑣,于是就誕生了O-R Mapping技術。這是一種妥協的結果,面向對象技術在數據庫領域無法取得成功,在面向對象開發語言中,就需要一種對象-關系映射技術。我相信,這種妥協產生的技術,會越來越流行。
我也認為,這是一個正確的選擇。就如高級語言不會嘗試取代匯編,無論高級語言有多好,最多在其上增加抽象層。例如Java使用bytecode、C#使用IL這樣,使用一種抽象層,而不是嘗試取代匯編。
O-R Mapping技術除了簡單映射之外,需要一種OQL,混合SQL和面向對象特征,提供映射方便的同時,保留關系數據庫提供的強大功能。例如聚合、排序等關系運算必須在OQL中提供。由于程序中的返回結果,有時不需要映射成對象,所以OQL必須提供另外一種功能,數據查詢。很多O-R Mappping產品都提供了基于對象的OQL和基于數據的OQL。
這導致包括三個部分:
1、應用程序使用OQL
2、O-R Mapping解釋或者編譯OQL
3、對象數據庫負責數據處理
如果O-R Mapping使用解釋的方式處理OQL,則會包括產生SQL、組裝對象等操作。效率通常都不會很好,現在的O-R Mapping產品基本都是基于解釋的方式處理。
如果O-R Mapping使用編譯的方式,可以優化產生SQL,動態創建SQL存儲過程,減少SQL交互的過程,能夠獲得很好的性能,可以做到比絕
大多數人直接使用SQL性能都要好。我曾經做過一個實驗性的實現,取得很好的效果,可惜由于種種原因,沒有繼續下去。
我認為,下一代的O-R Mapping產品,都將會采用編譯的方式,因為在很多情形下,特別是復雜對象的處理方面,可以有大幅度的性能提升,在某些場景下,可以數倍甚至數十倍的性能提升。
一直不是很看好Hibernate,因為其主要作者gavin對編譯技術不了解,2.x版本的HQL語法很搞笑,實現也是很搞笑的,簡單的文本替換,看到讓人目瞪口呆。3.0之后加入了HQL的AST(抽象語法樹),但這不是他本人的做的,其他愛好者加入進來,3.1還是沒有很好融合進來。之后的版本我就沒有繼續關注了。
我覺得O-R Mapping完全就是一種編譯技術,不懂編譯技術的人去作這件事清總會有些不妥。這不單是Hibernate的問題,也是其他O-R Mapping產品的問題。
我的觀點:
1、Java、C#、C++等語言在處理關系數據方面沒有優勢。SQL是關系數據處理的領域專用語言(DSL),更適合處理關系數據,提供強大的功能。
2、關系數據是主流,希望應用開發人員使用O-R Mapping,而不懂關系數據庫,這是不現實的。
3、O-R Mapping技術還有很大發展空間,以后在功能、性能等方面都會有重大提升,最終成熟。
文章來源:
http://www.cnblogs.com/jobs/archive/2007/04/23/723297.html
在操作系統中,有兩種不同的方法提供線程支持:用戶層的用戶線程,或內核層的內核線程。
其中用戶線程在內核之上支持,并在用戶層通過線程庫來實現。不需要用戶態/核心態切換,速度快。操作系統內核不知道多線程的存在,因此一個線程阻塞將使得整個進程(包括它的所有線程)阻塞。由于這里的處理器時間片分配是以進程為基本單位,所以每個線程執行的時間相對減少。
內核線程由操作系統直接支持。由操作系統內核創建、調度和管理。內核維護進程及線程的上下文信息以及線程切換。一個內核線程由于I/O操作而阻塞,不會影響其它線程的運行。
Java線程的實現是怎樣的呢?我們通過SUN Java 6的源碼了解其在Windows和Linux下的實現。
在Windows下的實現,os_win32.cpp中
// Allocate and initialize a new OSThread
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
unsigned thread_id;
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
}
// Initial state is ALLOCATED but not INITIALIZED
{
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
osthread->set_state(ALLOCATED);
}
// Initialize support for Java interrupts
HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL);
if (interrupt_event == NULL) {
delete osthread;
return NULL;
}
osthread->set_interrupt_event(interrupt_event);
osthread->set_interrupted(false);
thread->set_osthread(osthread);
if (stack_size == 0) {
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be changed with the flag -Xss
if (JavaThread::stack_size_at_create() > 0)
stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
// Create the Win32 thread
//
// Contrary to what MSDN document says, "stack_size" in _beginthreadex()
// does not specify stack size. Instead, it specifies the size of
// initially committed space. The stack size is determined by
// PE header in the executable. If the committed "stack_size" is larger
// than default value in the PE header, the stack is rounded up to the
// nearest multiple of 1MB. For example if the launcher has default
// stack size of 320k, specifying any size less than 320k does not
// affect the actual stack size at all, it only affects the initial
// commitment. On the other hand, specifying 'stack_size' larger than
// default value may cause significant increase in memory usage, because
// not only the stack space will be rounded up to MB, but also the
// entire space is committed upfront.
//
// Finally Windows XP added a new flag 'STACK_SIZE_PARAM_IS_A_RESERVATION'
// for CreateThread() that can treat 'stack_size' as stack size. However we
// are not supposed to call CreateThread() directly according to MSDN
// document because JVM uses C runtime library. The good news is that the
// flag appears to work with _beginthredex() as well.
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
#define STACK_SIZE_PARAM_IS_A_RESERVATION (0x10000)
#endif
HANDLE thread_handle =
(HANDLE)_beginthreadex(NULL,
(unsigned)stack_size,
(unsigned (__stdcall *)(void*)) java_start,
thread,
CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
&thread_id);
if (thread_handle == NULL) {
// perhaps STACK_SIZE_PARAM_IS_A_RESERVATION is not supported, try again
// without the flag.
thread_handle =
(HANDLE)_beginthreadex(NULL,
(unsigned)stack_size,
(unsigned (__stdcall *)(void*)) java_start,
thread,
CREATE_SUSPENDED,
&thread_id);
}
if (thread_handle == NULL) {
// Need to clean up stuff we've allocated so far
CloseHandle(osthread->interrupt_event());
thread->set_osthread(NULL);
delete osthread;
return NULL;
}
Atomic::inc_ptr((intptr_t*)&os::win32::_os_thread_count);
// Store info on the Win32 thread into the OSThread
osthread->set_thread_handle(thread_handle);
osthread->set_thread_id(thread_id);
// Initial thread state is INITIALIZED, not SUSPENDED
{
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
osthread->set_state(INITIALIZED);
}
// The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
return true;
}
可以看出,SUN JVM在Windows下的實現,使用_beginthreadex來創建線程,注釋中也說明了為什么不用“Window編程書籍推薦使用”的CreateThread函數。由此看出,Java線程在Window下的實現是使用內核線程。
而在Linux下又是怎樣的呢?
在os_linux.cpp文件中的代碼摘錄如下:
# include <pthread.h>
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
}
// set the correct thread state
osthread->set_thread_type(thr_type);
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
thread->set_osthread(osthread);
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// stack size
if (os::Linux::supports_variable_stack_size()) {
// calculate stack size if it's not specified by caller
if (stack_size == 0) {
stack_size = os::Linux::default_stack_size(thr_type);
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be changed with the flag -Xss
if (JavaThread::stack_size_at_create() > 0) stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
pthread_attr_setstacksize(&attr, stack_size);
} else {
// let pthread_create() pick the default value.
}
// glibc guard page
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
}
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
pthread_attr_destroy(&attr);
if (ret != 0) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
if (lock) os::Linux::createThread_lock()->unlock();
return false;
}
// Store pthread info into the OSThread
osthread->set_pthread_id(tid);
// Wait until child thread is either initialized or aborted
{
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
while ((state = osthread->get_state()) == ALLOCATED) {
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
}
if (lock) {
os::Linux::createThread_lock()->unlock();
}
}
// Aborted due to thread limit being reached
if (state == ZOMBIE) {
thread->set_osthread(NULL);
delete osthread;
return false;
}
// The thread is returned suspended (in state INITIALIZED),
// and is started higher up in the call chain
assert(state == INITIALIZED, "race condition");
return true;
}
Java在Linux下的線程的創建,使用了pthread線程庫,而pthread就是一個用戶線程庫,因此結論是,Java在Linux下是使用用戶線程實現的。
MessageDigest的選擇好多,包括MD2、MD4、MD5、SHA-1、SHA-256、RIPEMD128、RIPEMD160等等。我們如何選擇呢?
選擇考慮在兩個方面:安全、速度。
MD2很安全,但是速度極慢,一般不用。
速度方面,最快的是MD4,MD5比SHA-1快
速度排名:MD4 > MD5 > RIPEMD-128 > SHA-1 > REPEMD-160
按照《應用密碼學手冊》提供的表格數據為:
MD4 長度 128 相對速度 1
MD5 長度 128 相對速度 0.68
REPEMD-128 長度 128 相對速度 0.39
SHA-1 長度 160 相對速度 0.29
REPEMD-160 長度 160 相對速度 0.24
我親自測試的結果和《應用密碼學手冊》提供的數據接近。
MD4已經很早證明有缺陷,很少使用,最流行的是MD5和SHA-1,但MD5和SHA1也被王小云找到碰撞,證實不安全。
傳說SHA-1比MD5要安全,但是SHA-1有美國國家安全局的背景,有人懷疑這個算法背后有不可告人的秘密,我也是陰謀論者之一,傾向選擇MD5而不是SHA-1。王小云找到SHA-1碰撞之后,可以說傳說的謠言破滅了,而且MD5速度要比SHA-1快差不多一倍,沒有什么理由選擇SHA-1。
----------------------------------
在Java的現實環境中是怎樣?
在SUN的JCE實現中,只提供了MD2、MD5、SHA-1,SHA-256等常用的MessageDigest算法。
開源的JCE實現bouncycastle則提供了眾多的實現,包括MD整個系列,SHA整個系列,RIPEMD整個系列。
很多的開源項目都帶一個bcprov-jdk14.jar的包,可以說bouncycastle應用很廣泛。SUN公司的一些項目也用了bouncycastle,例如JXTA。
但實際上,SUN的實現包括了MD4,但你需要這樣使用:
MessageDigest md = sun.security.provider.MD4.getInstance();
但是,JDK帶實現性能要比bouncycastle性能好得多,相差速度通常超過一倍以上,我測試過MD5、SHA1和MD4,其性能差別都是類似,一倍多。
比較的結論:
bouncycastle開源免費,提供算法多,但速度較慢
SUN JCE提供的實現,包括了流行常用算法,速度很快,同類型算法比bouncycastle要快一倍以上。
----------------------------------
結論:
又要安全又要速度,選擇MD5
追求安全,不在意速度,相信傳說,不相信陰謀論,選擇SHA系列
追求速度,安全次之,可以選擇MD4。
----------------------------------
現實例子:
emule采用MD4和SHA-1兩種結合使用
apache之類的技術網站,提供下載的文件,同時提供一個校驗文件.md5
不是使用每連接一線程的技術,而是使用多路復用技術。
作了一個分配算法。第一個HTTP Request返回取得ContentLength之后,如果使用多個連接下載,則需要一個分配算法,分配每個Request所對應的Range。分配的部分可能是一個連續的塊,例如bytes=100-999,也可能是一些碎塊,例如bytes=500-600,700-800,850-999。為此,我做了一個數據結構,其提供的功能類似java.util.BitSet,也支持and、or等操作。
實現了對ContentType為multipart/bytes的HTTP Message Body的解釋。如果發送HTTP Request,Range為多個不連續的部分,返回的HTTP Message,就會是multipart,每個part都會包括一個Head和一個Body,需要一個解析器。
下一步就是把HTTP下載加入P2P下載中!
最近編碼更流暢了。原因包括:
1) 絕大多數時候純鍵盤操作,Eclipse 200多個快捷鍵,我熟練使用絕大部分,編碼的過程,如同行云流水般。
2)掌握了更多的解決問題的辦法,有了更廣的知識面,編碼時,信手拈來。最近一年里,掌握了很多知識,包括并發、網絡、操作系統等等方面的知識。
3)組織代碼的能力更強了,最近對于大型復雜的程序,組織代碼的能力更強了,組織程序的能力包括,更好的結構,更好的擴展性,可測試性,可管理性等等。
a) 在編碼的過程中,使得更多的模塊可以單獨于整個環境獨立測試
b) 精心處理過的LOG,使得代碼更容易跟蹤,排錯。
c) 復雜的模塊,附帶監控管理界面,使得排錯和優化都更為方便。
d) 使用制作狀態轉換表的手段,清晰化復雜的狀態處理。在前些年設計/實現工作流引擎時,就開始使用狀態轉換表描述狀態機,但現在面臨的狀態機復雜。
貼圖的實現方式為:
1、把剪切板中的圖片存在本地的SendingImages目錄,存放的格式使用PNG,當然可以其他格式,但是PNG格式更小。
2、使用MD5算法產生一個ImageID。當然可以使用SHA1等其他算法
3、把imageID發送remote peer
4、當remote peer收到imageID時,檢查本地ReceivedImage目錄,如果已經存在,顯示圖片,不存在則發送一個RequestImage請求,并在聊天記錄中顯示一個等待信息(為一個GIF動畫)。
5、本地Peer收到RequestImage請求之后,發送圖片數據。如果圖片大于64K,則分塊發送。
6、remote peer收到圖像數據之后,進行校驗,看是否正確。
7、校驗通過后,把圖片在聊天面板上顯示(替換等待圖片)
預定義表情的實現很簡單,自定義表情的實現和貼圖實現一致,只是少了從剪貼板保存圖片的過程。
上一篇博客寫了我一些關于P2P下載以及平臺的思考,有這樣的思考,是因為我正在做一件這樣的事情。
我介紹一下我正在做的事情吧:
1、基于JXTA,我崇拜Bill Joy,學習JXTA就是因為我崇拜他,之后覺得這個技術很棒。但是JXTA存在一些用戶不友好的地方,包括JXTA的ConfigDialog和DialogAuthenticator是十分用戶不友好的,我重寫了這些部分。雖然是一些無關痛癢的地方,但是可以改變用戶體驗,提高用戶友好性。
2、簡單的插件機制,我做了一個簡單的插件系統,Application啟動之后挨個裝載服務,UI也是服務之一,UI也是基于插件的,在微內核框架流行的今天,使用一個簡單的插件機制似乎不是太好,等過一段時間之后考慮使用osgi替代之。
3、提供了兩個功能,聊天和文件共享下載。這兩個功能分別表現為兩個JXTA的Service。
4、聊天功能。目前還比較簡單,只實現了不帶格式的文本聊天,但是我隨后會加入帶格式的文本聊天,也將會加入類似騰訊QQ那樣的貼圖支持,自定義表情支持,騰訊QQ的實現很巧妙,但并不困難。四月初的版本就有可能實現之。
5、共享和下載。目前實現了文件和文件夾的共享。其中包括了高級智能錯誤檢測(AICH)等。傳輸協議參考了BT和emule的協議。在界面中還實現對DragAndDrop支持,從Windows Explore中拖一個文件到目錄共享的面板,即開始共享該文件。
6、存儲信息采用apache的Derby數據庫。我很喜歡Berkeley DB,Berkely DB高效簡潔,但是License不開放。我最終還是采用Derby了,采用Derby將會帶來一系列好處,SQL支持、JDBC支持等等,License無限制等等。擴展的應用基于其上也十分方便。由于我曾經開發過多數據庫支持引擎KSQL,在KSQL上增加支持Derby的翻譯是很容易的事情。如此一來,可能存儲引擎部分,將有可能擴展到KSQL目前所支持的多種數據庫,包括嚴格測試過的Oracle、DB2、MS SQL Server,還有經過簡單測試支持Sybase、PostgreSQL、MySQL。
7、最近的JXTA Java SE 2.5版本,使用了nio來管理連接,也就說,使用了多路復用的技術,使得每個Peer創建大量連接成為可能,例如Windows下默認最大的多路復用支持1024個連接。而Linux下,java nio是使用epoll實現的,并發性能將更好,這對于聚合點來說很重要。普通的Peer部署在Linux下可能較少,但是聚合點部署在Linux完全是可能的。
8、使用Swing做界面,使用Java 6 SE的Swing,做了系統托盤Tray的支持等等。由于Swing的UI設計工具很不穩定,最終完全手工編寫UI部分代碼,雖然辛苦,但是代碼簡潔,不同UI Designer生成的那樣。
9、我期望4月初發布一個版本,提供一個基本可用的版本。
10、我是從1月初開始學習JXTA的,到現在還不滿3個月,其中還包括過年回家休息等等,玩游戲沉迷等等,但總的來說,我對這個學習速度很滿意。不過其中感覺最爽的是,在這個過程中,編碼時,基本純鍵盤操作,不用鼠標,如行云流水一邊,十分流暢,工作效率高,人也舒服。