COOVOl技术论坛 » Java » Java 5.0 多线程编程实践 (转到动态网页)
« 1 2» Pages: ( 1/2 total )
本页主题: Java 5.0 多线程编程实践 加为IE收藏 | 收藏主题 | 上一主题 | 下一主题

ketty0926
级别: 精灵王

 Java 5.0 多线程编程实践

Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活。本文通过一个网络服务器模型,来实践Java5的多线程编程,该模型中使用了Java5中的线程池,阻塞队列,可重入锁等,还实践了Callable, Future等接口,并使用了Java 5的另外一个新特性泛型。

  简介

  本文将实现一个网络服务器模型,一旦有客户端连接到该服务器,则启动一个新线程为该连接服务,服务内容为往客户端输送一些字符信息。一个典型的网络服务器模型如下:

  1. 建立监听端口。

  2. 发现有新连接,接受连接,启动线程,执行服务线程。 3. 服务完毕,关闭线程。

  这个模型在大部分情况下运行良好,但是需要频繁的处理用户请求而每次请求需要的服务又是简短的时候,系统会将大量的时间花费在线程的创建销毁。Java 5的线程池克服了这些缺点。通过对重用线程来执行多个任务,避免了频繁线程的创建与销毁开销,使得服务器的性能方面得到很大提高。因此,本文的网络服务器模型将如下:

  1. 建立监听端口,创建线程池。

  2. 发现有新连接,使用线程池来执行服务任务。

  3. 服务完毕,释放线程到线程池。

  下面详细介绍如何使用Java 5的concurrent包提供的API来实现该服务器。

  初始化

  初始化包括创建线程池以及初始化监听端口。创建线程池可以通过调用java.util.concurrent.Executors类里的静态方法newChahedThreadPool或是newFixedThreadPool来创建,也可以通过新建一个java.util.concurrent.ThreadPoolExecutor实例来执行任务。这里我们采用newFixedThreadPool方法来建立线程池。

ExecutorService pool = Executors.newFixedThreadPool(10);

  表示新建了一个线程池,线程池里面有10个线程为任务队列服务。

  使用ServerSocket对象来初始化监听端口。

private static final int PORT = 19527;
serverListenSocket = new ServerSocket(PORT);
serverListenSocket.setReuseAddress(true);
serverListenSocket.setReuseAddress(true);

  服务新连接

  当有新连接建立时,accept返回时,将服务任务提交给线程池执行。

while(true){
 Socket socket = serverListenSocket.accept();
 pool.execute(new ServiceThread(socket));
}

  这里使用线程池对象来执行线程,减少了每次线程创建和销毁的开销。任务执行完毕,线程释放到线程池。

  服务任务

  服务线程ServiceThread维护一个count来记录服务线程被调用的次数。每当服务任务被调用一次时,count的值自增1,因此ServiceThread提供一个increaseCount和getCount的方法,分别将count值自增1和取得该count值。由于可能多个线程存在竞争,同时访问count,因此需要加锁机制,在Java 5之前,我们只能使用synchronized来锁定。Java 5中引入了性能更加粒度更细的重入锁ReentrantLock。我们使用ReentrantLock保证代码线程安全。下面是具体代码:


代码:
private static ReentrantLock lock = new ReentrantLock ();
private static int count = 0;
private int getCount(){
 int ret = 0;
 try{
  lock.lock();
  ret = count;
 }finally{
  lock.unlock();
 }
 return ret;
}
private void increaseCount(){
 try{
  lock.lock();
  ++count;
 }finally{
  lock.unlock();
 }
}  服务线程在开始给客户端打印一个欢迎信息,

[code]increaseCount();
int curCount = getCount();
helloString = "hello, id = " + curCount+"\r\n";
dos = new DataOutputStream(connectedSocket.getOutputStream());
dos.write(helloString.getBytes());[code]

  然后使用ExecutorService的submit方法提交一个Callable的任务,返回一个Future接口的引用。这种做法对费时的任务非常有效,submit任务之后可以继续执行下面的代码,然后在适当的位置可以使用Future的get方法来获取结果,如果这时候该方法已经执行完毕,则无需等待即可获得结果,如果还在执行,则等待到运行完毕。


代码:

ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(new TimeConsumingTask());
dos.write("let's do soemthing other".getBytes());
String result = future.get();
dos.write(result.getBytes());

  其中TimeConsumingTask实现了Callable接口

class TimeConsumingTask implements Callable {
 public String call() throws Exception {
  System.out.println("It's a time-consuming task, you'd better retrieve your result in the furture");
  return "ok, here's the result: It takes me lots of time to produce this result";
 }
}

这里使用了Java 5的另外一个新特性泛型,声明TimeConsumingTask的时候使用了String做为类型参数。必须实现Callable接口的call函数,其作用类似与Runnable中的run函数,在call函数里写入要执行的代码,其返回值类型等同于在类声明中传入的类型值。在这段程序中,我们提交了一个Callable的任务,然后程序不会堵塞,而是继续执行dos.write("let's do soemthing other".getBytes());当程序执行到String result = future.get()时如果call函数已经执行完毕,则取得返回值,如果还在执行,则等待其执行完毕。
  服务器端的完整实现

  服务器端的完整实现代码如下:



代码:

package com.andrew;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class Server {
 private static int produceTaskSleepTime = 100;
 private static int consumeTaskSleepTime = 1200;
 private static int produceTaskMaxNumber = 100;
 private static final int CORE_POOL_SIZE = 2;
 private static final int MAX_POOL_SIZE = 100;
 private static final int KEEPALIVE_TIME = 3;
 private static final int QUEUE_CAPACITY = (CORE_POOL_SIZE + MAX_POOL_SIZE) / 2;
 private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
 private static final String HOST = "127.0.0.1";
 private static final int PORT = 19527;
 private BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY);
 //private ThreadPoolExecutor serverThreadPool = null;
 private ExecutorService pool = null;
 private RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.DiscardOldestPolicy();
 private ServerSocket serverListenSocket = null;
 private int times = 5;
 public void start() {
  // You can also init thread pool in this way.
  /*serverThreadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
  MAX_POOL_SIZE, KEEPALIVE_TIME, TIME_UNIT, workQueue,
  rejectedExecutionHandler);*/
  pool = Executors.newFixedThreadPool(10);
  try {
   serverListenSocket = new ServerSocket(PORT);
   serverListenSocket.setReuseAddress(true);

   System.out.println("I'm listening");
   while (times-- > 0) {
    Socket socket = serverListenSocket.accept();
    String welcomeString = "hello";
    //serverThreadPool.execute(new ServiceThread(socket, welcomeString));
    pool.execute(new ServiceThread(socket));
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  cleanup();
 }

 public void cleanup() {
  if (null != serverListenSocket) {
   try {
    serverListenSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
  //serverThreadPool.shutdown();
  pool.shutdown();
 }

 public static void main(String args[]) {
  Server server = new Server();
  server.start();
 }
}

class ServiceThread implements Runnable, Serializable {
 private static final long serialVersionUID = 0;
 private Socket connectedSocket = null;
 private String helloString = null;
 private static int count = 0;
 private static ReentrantLock lock = new ReentrantLock();

 ServiceThread(Socket socket) {
  connectedSocket = socket;
 }

 public void run() {
  increaseCount();
  int curCount = getCount();
  helloString = "hello, id = " + curCount + "\r\n";

  ExecutorService executor = Executors.newSingleThreadExecutor();
  Future<String> future = executor.submit(new TimeConsumingTask());

  DataOutputStream dos = null;
  try {
   dos = new DataOutputStream(connectedSocket.getOutputStream());
   dos.write(helloString.getBytes());
   try {
    dos.write("let's do soemthing other.\r\n".getBytes());
    String result = future.get();
    dos.write(result.getBytes());
   } catch (InterruptedException e) {
    e.printStackTrace();
   } catch (ExecutionException e) {
    e.printStackTrace();
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } finally {
   if (null != connectedSocket) {
    try {
     connectedSocket.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   if (null != dos) {
    try {
     dos.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
   executor.shutdown();
  }
 }

 private int getCount() {
  int ret = 0;
  try {
   lock.lock();
   ret = count;
  } finally {
   lock.unlock();
  }
  return ret;
 }

 private void increaseCount() {
  try {
   lock.lock();
   ++count;
  } finally {
   lock.unlock();
  }
 }
}

class TimeConsumingTask implements Callable<String> {
 public String call() throws Exception {
  System.out.println("It's a time-consuming task, you'd better retrieve your result in the furture");
  return "ok, here's the result: It takes me lots of time to produce this result";
 }

} 运行程序
运行服务端,客户端只需使用telnet 127.0.0.1 19527 即可看到信息如下:
上传的图像

没有你,我依然是个骄傲的公主。
顶端 Posted: 2008-08-23 22:31 | From:陕西省西安市 [楼 主]
abcd531
级别: 侠客

 软件加密狗解破思路和方法 联系电话15988877770联系QQ1167388

软件加密狗解破思路和方法

本文介绍的是软件加密狗解破的一般思路和方法,大家可能奇怪,昨天刚刚介绍完“软件加密锁产品评测”,怎么今天就介绍加密狗
解破知识?其实做为软件开发者,研究好软件加密的确很重要,不过也很有必要多了解一些关于加密狗解密和解破的知识,加密和解
破就像矛和盾一样,对于解密知识了解的越多,那么编写的加密代码就越好,要知道加密永远都比解密要容易的多,只有知己知彼,
方能百战百胜。
    解破高手前辈联系电话15988877770 联系QQ1167388    需要解破加密锁软件请联系我

  硬件加密锁,俗程“加密狗”,对于加密狗的解破大致可以分为三种方法,一种是通过硬件克隆或者复制,一种是通过SoftICE
等Debug工具调试跟踪解密,一种是通过编写拦截程序修改软件和加密狗之间的通讯。

  硬件克隆复制主要是针对国产芯片的加密狗,因为国产加密狗公司一般没有核心加密芯片的制造能力,因此有些使用了市场上通
用的芯片,解破者分析出芯片电路以及芯片里写的内容后,就可以立刻复制或克隆一个完全相同的加密狗。不过国外的加密狗就无法
使用这种方法,国外加密狗硬件使用的是安全性很好的自己研制开发的芯片,通常很难进行复制,而且现在国内加密狗也在使用进口
的智能卡芯片,因此这种硬件克隆的解密方法用处越来越少。
    解破高手前辈联系电话15988877770 联系QQ1167388    需要解破加密锁软件请联系我

  对于Debug调试解破,由于软件的复杂度越来越高,编译器产生的代码也越来越多,通过反汇编等方法跟踪调式解破的复杂度已
经变得越来越高,解破成本也越来越高,目前已经很少有人愿意花费大量精力进行如此复杂的解破,除非被解破的软件具有极高的价
值。

    解破高手前辈联系电话15988877770 联系QQ1167388    需要解破加密锁软件请联系我
  目前加密锁(加密狗)的解密解破工作主要集中在应用程序与加密动态库之间的通讯拦截。这种方法成本较低,也易于实现,对
待以单片机等芯片为核心的加密锁(加密狗)具有不错的解密效果。

  由于加密锁(加密狗)的应用程序接口(API)基本上都是公开的,因此从网上可以很容易下载到加密狗的编程接口API、用户手
册、和其它相关资料,还可以了解加密狗技术的最新进展。

  例如,某个国内知名的美国加密狗提供商的一款很有名的加密狗,其全部编程资料就可以从网上获取到,经过对这些资料的分析
,我们知道这个加密锁(加密狗)有64个内存单元,其中56个可以被用户使用,这些单元中的每一个都可以被用为三种类型之一:算
法、数据值和计数器。

  数据值比较好理解,数据值是用户存储在可读写的单元中的数据,就和存储在硬盘里一样,用户可以使用Read函数读出存储单元
里面的数据,也可以使用Write函数保存自己的信息到存储单元。

  计数器是这样一种单元,软件开发商在其软件中使用Decrement函数可以把其值减一,当计数器和某种活动的(active)算法关
联时,计数器为零则会封闭(deactive)这个算法。

  算法单元较难理解一些,算法(algorithm)是这样一种技术,你用Query(queryData)函数访问它,其中queryData是查询值,
上述函数有一个返回值,被加密的程序知道一组这样的查询值/返回值对,在需要加密的地方,用上述函数检查狗的存在和真伪。对
于被指定为算法的单元,软件上是无法读和修改的,即使你是合法的用户也是如此,我理解这种技术除了增加程序复杂性以外,主要
是为了对付使用模拟器技术的解破。

  此加密锁(加密狗)的所有API函数调用都会有返回值,返回值为0的时候表示成功。
  因此,解破思路就出来了,就是使用我们自己的工具(如VB、VC等)重新编写构造一个和加密狗API一样的DLL动态库文件,里面
也包含Read、Write等全部API中包含的函数,使用的参量及返回值和原来的函数一样,所有函数返回零。然后对Query、Read函数进
行处理,返回应用软件需要的数值即可。

  这个新的DLL文件编写成功后,直接替换掉原来的DLL文件,这时候再运行应用软件,软件访问加密狗的操作就全部会被拦截,拦
截程序永远会返回正确的数据给软件,从而实现了模拟加密狗的运行。

  以上是目前解破软件加密狗(加密锁)的一些常见思路,对于这种解破,软件开发者还是有相应的一些对策的,下一回我将在《
软件加密锁编程技巧》一文中具体介绍一下软件开发者将如何编写安全可靠的代码,使得这种类似的解破方法失效。

解破高手前辈联系电话15988877770 联系QQ1167388    需要解破加密锁软件请联系我
顶端 Posted: 2008-09-24 00:45 | From:浙江省杭州市 1 楼
reghongkong
级别: 新手上路

 喂蚊子

姑姑在卧室里喷上灭蚊药,带侄女出去散步。
路上,侄女不解的问:“姑姑,你为什么不买二斤肉挂在家里,让蚊子吃饱,它不就不咬咱们了吗?”
孕妇装
孕妇服
孕妇装孕妇服饰
防辐射孕妇装
孕妇装
顶端 Posted: 2008-10-02 11:45 | From:上海市嘉定区 2 楼
abcd667
级别: 侠客

 日常生活饮食误区生活常识

[size=14px]如今,科学饮食是人们关心的热点问题。但是,在人们的日常生活中,还是存在许多不良的饮食习惯和值得怀疑的建议,从而影响了人们的健康。在这里,我们就列举一些日常生活的饮食误区,供大家参考。
  用小火炒菜营养损失少
  维生素C、维生素B1都怕热,怕煮。据测定,大火快炒的菜,维生素C损失仅17%,若炒后再焖,菜里的维生素C将损失59%。所以炒菜要用旺火
水果机上分器,这样炒出来的菜,不仅色美味好,而且菜里的营养损失也少。烧菜时加少许醋,也有利于维生素的保存。
  劳累后补鱼肉
  体力劳动或大运动量后,有许多人要吃大鱼大肉等油腻食品来补养。这种做法也是不健康的,因为大鱼大肉为酸性食物,可使血液酸化
老虎ji上分器,加之运动后产生的大量乳酸物质,会引起机体酸中毒,加重疲劳程度。
  水果当正餐是健康时尚
  时下,有些爱美怕胖的女士,中午只吃个苹果或香蕉,就算正餐了。专家指出,绝大部分水果所含蛋白质、铁、维生素B12很少,长期以水果当正餐易导致贫血或营养不良。
  牛奶能治疗胃溃疡
  牛奶能中和消化道
水果机遥控器中的酸性物质,因而能暂时缓解疼痛,然而牛奶中含有的钙反而会增加上述酸性物质,结果就是一段时间后疼痛症状更加明显。
  牛奶和豆类混食有毒
  无论是牛奶还是豆子在被消化时都会在体内释放大量气体
老虎ji定位器,刺激肠道蠕动。将二者混食会引起腹痛老虎ji等症状,但不存在毒性。
  吃豆芽丢弃豆瓣
  有人只吃上面的芽而将豆瓣丢掉。事实上,豆瓣中含维生素C比芽的部分多2-3倍。
  啤酒或橙汁里加生鸡蛋有营养
  生鸡蛋不容易消化,而且在营养价值上同煮熟的鸡蛋没有区别。

  转自www.my88888.com/lhjsfq.htm//www.my88888.com/sgjsfq.htm//www.my88888.com/sgjykq.htm//www.my88888.com/lhjdwq.htm//www.my88888.com/lhj.htm
顶端 Posted: 2008-10-03 17:57 | From:黑龙江省牡丹江市 3 楼
ijkl692
级别: 骑士

 带状疱疹

 带状疱疹是一种沿某一周围神经分布,以群集性单侧带状分布,一般不超过中线,伴明显疼痛为主要表现的病毒性疾病。皮肤科医生尤以中老年较多,年龄越大,疼痛越重,许多患者在皮损完全消退后,仍留有后遗神经痛,此种后遗神经痛可持续数月之久,北京银屑病医院甚至数年。早发现、早诊断及早治疗是缩短病程、减轻后遗神经痛的关键。

  中老年人群当警惕!入秋勤锻炼增强免疫力

  据皮肤科专家介绍,北京皮肤病医院通过采用氦氖激光局部照射,这20名带状疱疹患者已经全部治愈出院。但目前是入秋时节,正值带状疱疹高发期,中老年人在患有某些疾病期间,身体的免疫力会下降,最易感染带状疱疹。因此,入秋后中老年人要警惕,一旦发现一侧躯体出现不明原因的疼痛时,北京皮肤病别忘了及时到皮肤科进行相关诊断和治疗,以期早发现早治疗早康复。

  要预防带状疱疹,皮肤划痕症中老年人还应加强体育锻炼,注意饮食营养的均衡,保持心情舒畅和避免过度劳累,从而增强机体的抗病能力,以免给带状疱疹病毒造成可乘之机。
顶端 Posted: 2008-10-06 10:34 | From:福建省福州市 4 楼
zhucemail
级别: 骑士

 不要赊售

生搬硬套    有个人以杀牛为业,他去看望一个杀猪的朋友。朋友不在家,他儿子讳忌“杀猪”两个
字,便对杀牛的说:“家父出亥去了。”杀牛的回来后,对自己的儿子说这件事,并称赞不
已,儿子也明白了这样说话显得文雅。
    第二天,杀猪的来看杀牛的,正好杀牛的出去干活了,他儿子便对杀猪的说:“家父到
外面出丑去了。”杀猪的问:“什么时候回来?”回答是:“出尽了丑,自然就回来了。”
                                        ——清·游戏主人《笑林广记》

不要赊售    有个老翁,一辈子省吃俭用,为儿孙做牛马,积下了一份家产。临终之时,他把儿子们
叫到身边,问道:“我死之后,你们应该怎样为我办丧事?”
    大儿子说:“我们十分理解父亲大人的节省之心,不敢铺张浪费,只用缟衣布被,二寸
之棺,一寸之椁,墓道也只用土封。”老翁皱了半天眉,嫌这样太奢侈。
    二儿子说:“衣服、被子和棺椁,一律都不用,只用草帘子卷起来,送到郊外火葬就行
了。”老翁还是嫌花费太多。
    三儿子领会了父亲的意思,便委婉地说:“父亲大人爱子之心,无微不至。既然生前尽
心竭力,死后难道舍不得一个躯体?不如把父亲的遗体分成三份,给我们兄弟三个,也算一
份遗产。”老翁听了,大笑道:“我儿这番话,正合我意。”
    过了一会儿,又嘱咐说:
    “对门王三老,惯赖肉钱,千万不要赊给他。”
                                        ——清·游戏主人《笑林广记》

捣蒜抽葱    明成化年间,太监汪直权势很大,许多朝廷大臣争着巴结他。汪直巡察边地,所到之地
的都御史全都身着戎装到二三百里之外迎候,而且望尘下拜,半跪在路边,如同奴仆。本来
该行的揖让之礼,这时竟没有谁用了。当时的人们作了一副对联形容这种情况:
    “都宪叩头如捣蒜,侍郎曲膝似抽葱。”
                                        ——清·粱恭辰《巧对续录》。
__________________________________________________________________________
提供管道泵、家用管道泵、热水管道泵、氟塑料泵 、氟塑料离心泵产品、氟塑料离心泵工厂、 上海真空泵厂、自动搅匀潜水排污泵、氟塑料离心泵 、氟塑料离心泵产品、氟塑料离心泵工厂、耐腐蚀泵、耐腐蚀泵、衬胶耐腐蚀泵、化工耐腐蚀泵等产品。
我的贴子我做主!
顶端 Posted: 2008-10-07 16:21 | From:浙江省杭州市 5 楼
airpiaowu003
级别: 骑士

 417

学习了,赞一个。

SIGNRTURE_________________________________________________________

我的其它文章:东航头等舱特价-东航公务舱特价南航头等舱特价-南航公务舱特价北京到蒙特利尔特价机票北京到多伦多特价机票北京到温哥华特价机票
顶端 Posted: 2008-10-26 10:22 | From:北京市 6 楼
zoo4456
级别: 新手上路

 热电偶

顶端 Posted: 2008-11-03 11:18 | From:福建省厦门市 7 楼
ilinda85
级别: 新手上路

 哈,不错!很赞!

哈,不错!很赞!
 在17世纪以前,英国的铁观音茶叶都是从中国进口的,路途遥远,进口量又有限,使得铁观音茶叶在当时的英国成为了一种奢侈品.但是铁观音茶叶在英国的待遇如下:在某贵妇的家庭沙龙中,由一名身穿燕尾服的管家捧进一只精美的匣子和一套一般来说是会镶金的茶具.然后,由女主人亲自从匣子中取出一点点茶叶放入壶中.接下来大家就会一杯杯的喝茶,直喝到一点茶味都没有为止.这还不算,接着女主人会用一只精致的夹子把壶中的茶叶夹出,分几份夹在面包里在抹上黄油,供大家品尝.这时英国的名流们就会一个个拿起茶叶渣子做的三明治,啧啧的吃着,称赞着. 
Linda
顶端 Posted: 2008-11-04 17:36 | From:福建省厦门市 8 楼
lao1abc
级别: 侠客

 楼主的帖太好了 顶顶顶顶顶顶

楼主的帖太好了 我来顶,顺便介绍几个好玩的游戏:传奇世界 这个游戏很不错哦,还有QQ自由幻想外挂站 好玩,人气超级旺盛的--DNF地下城与勇士外挂站,最后在介绍个新游戏,非常经典的哦传奇外传外挂站 ,这几个都相当的不错,喜欢的可以去看看!!!
顶端 Posted: 2008-11-11 18:14 | From:江西省吉安市 9 楼
« 1 2» Pages: ( 1/2 total )
COOVOl技术论坛 » Java
快速发帖 顶端
内容
HTML 代码不可用

使用签名
Wind Code自动转换

字数检查 恢复数据
按 Ctrl+Enter 直接提交
表情 [更多]

Powered by PHPWind v6.3.2 Code © 2003-08 PHPWind
This is html template view this page faster