Java Socket编程实例(三)- TCP服务端线程池

一、服务端回传服务类:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger; 

public class EchoProtocol implements Runnable {
  private static final int BUFSIZE = 32; // Size (in bytes) of I/O buffer
  private Socket clientSocket; // Socket connect to client
  private Logger logger; // Server logger 

  public EchoProtocol(Socket clientSocket, Logger logger) {
    this.clientSocket = clientSocket;
    this.logger = logger;
  } 

  public static void handleEchoClient(Socket clientSocket, Logger logger) {
    try {
      // Get the input and output I/O streams from socket
      InputStream in = clientSocket.getInputStream();
      OutputStream out = clientSocket.getOutputStream(); 

      int recvMsgSize; // Size of received message
      int totalBytesEchoed = 0; // Bytes received from client
      byte[] echoBuffer = new byte[BUFSIZE]; // Receive Buffer
      // Receive until client closes connection, indicated by -1
      while ((recvMsgSize = in.read(echoBuffer)) != -1) {
        out.write(echoBuffer, 0, recvMsgSize);
        totalBytesEchoed += recvMsgSize;
      } 

      logger.info("Client " + clientSocket.getRemoteSocketAddress() + ", echoed " + totalBytesEchoed + " bytes."); 

    } catch (IOException ex) {
      logger.log(Level.WARNING, "Exception in echo protocol", ex);
    } finally {
      try {
        clientSocket.close();
      } catch (IOException e) {
      }
    }
  } 

  public void run() {
    handleEchoClient(this.clientSocket, this.logger);
  }
}

二、每个客户端请求都新启一个线程的Tcp服务端:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Logger; 

public class TCPEchoServerThread { 

  public static void main(String[] args) throws IOException {
    // Create a server socket to accept client connection requests
    ServerSocket servSock = new ServerSocket(5500); 

    Logger logger = Logger.getLogger("practical"); 

    // Run forever, accepting and spawning a thread for each connection
    while (true) {
      Socket clntSock = servSock.accept(); // Block waiting for connection
      // Spawn thread to handle new connection
      Thread thread = new Thread(new EchoProtocol(clntSock, logger));
      thread.start();
      logger.info("Created and started Thread " + thread.getName());
    }
    /* NOT REACHED */
  }
}

三、固定线程数的Tcp服务端:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger; 

public class TCPEchoServerPool {
  public static void main(String[] args) throws IOException {
    int threadPoolSize = 3; // Fixed ThreadPoolSize 

    final ServerSocket servSock = new ServerSocket(5500);
    final Logger logger = Logger.getLogger("practical"); 

    // Spawn a fixed number of threads to service clients
    for (int i = 0; i < threadPoolSize; i++) {
      Thread thread = new Thread() {
        public void run() {
          while (true) {
            try {
              Socket clntSock = servSock.accept(); // Wait for a connection
              EchoProtocol.handleEchoClient(clntSock, logger); // Handle it
            } catch (IOException ex) {
              logger.log(Level.WARNING, "Client accept failed", ex);
            }
          }
        }
      };
      thread.start();
      logger.info("Created and started Thread = " + thread.getName());
    }
  }
}

四、使用线程池(使用Spring的线程次会有队列、最大线程数、最小线程数和超时时间的概念)

1.线程池工具类:

import java.util.concurrent.*; 

/**
 * 任务执行者
 *
 * @author Watson Xu
 * @since 1.0.0 <p>2013-6-8 上午10:33:09</p>
 */
public class ThreadPoolTaskExecutor { 

  private ThreadPoolTaskExecutor() { 

  } 

  private static ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
    int count; 

    /* 执行器会在需要自行任务而线程池中没有线程的时候来调用该程序。对于callable类型的调用通过封装以后转化为runnable */
    public Thread newThread(Runnable r) {
      count++;
      Thread invokeThread = new Thread(r);
      invokeThread.setName("Courser Thread-" + count);
      invokeThread.setDaemon(false);// //???????????? 

      return invokeThread;
    }
  }); 

  public static void invoke(Runnable task, TimeUnit unit, long timeout) throws TimeoutException, RuntimeException {
    invoke(task, null, unit, timeout);
  } 

  public static <T> T invoke(Runnable task, T result, TimeUnit unit, long timeout) throws TimeoutException,
      RuntimeException {
    Future<T> future = executor.submit(task, result);
    T t = null;
    try {
      t = future.get(timeout, unit);
    } catch (TimeoutException e) {
      throw new TimeoutException("Thread invoke timeout ...");
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return t;
  } 

  public static <T> T invoke(Callable<T> task, TimeUnit unit, long timeout) throws TimeoutException, RuntimeException {
    // 这里将任务提交给执行器,任务已经启动,这里是异步的。
    Future<T> future = executor.submit(task);
    // System.out.println("Task aready in thread");
    T t = null;
    try {
      /*
       * 这里的操作是确认任务是否已经完成,有了这个操作以后
       * 1)对invoke()的调用线程变成了等待任务完成状态
       * 2)主线程可以接收子线程的处理结果
       */
      t = future.get(timeout, unit);
    } catch (TimeoutException e) {
      throw new TimeoutException("Thread invoke timeout ...");
    } catch (Exception e) {
      throw new RuntimeException(e);
    } 

    return t;
  }
} 

2.具有伸缩性的Tcp服务端:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger; 

import demo.callable.ThreadPoolTaskExecutor; 

public class TCPEchoServerExecutor { 

  public static void main(String[] args) throws IOException {
    // Create a server socket to accept client connection requests
    ServerSocket servSock = new ServerSocket(5500); 

    Logger logger = Logger.getLogger("practical"); 

    // Run forever, accepting and spawning threads to service each connection
    while (true) {
      Socket clntSock = servSock.accept(); // Block waiting for connection
      //executorService.submit(new EchoProtocol(clntSock, logger));
      try {
        ThreadPoolTaskExecutor.invoke(new EchoProtocol(clntSock, logger), TimeUnit.SECONDS, 3);
      } catch (Exception e) {
      }
      //service.execute(new TimelimitEchoProtocol(clntSock, logger));
    }
    /* NOT REACHED */
  }
}

以上就是本文的全部内容,查看更多Java的语法,大家可以关注:《Thinking in Java 中文手册》、《JDK 1.7 参考手册官方英文版》、《JDK 1.6 API java 中文参考手册》、《JDK 1.5 API java 中文参考手册》,也希望大家多多支持我们。

(0)

相关推荐

  • Java线程池使用与原理详解

    线程池是什么? 我们可以利用java很容易创建一个新线程,同时操作系统创建一个线程也是一笔不小的开销.所以基于线程的复用,就提出了线程池的概念,我们使用线程池创建出若干个线程,执行完一个任务后,该线程会存在一段时间(用户可以设定空闲线程的存活时间,后面会介绍),等到新任务来的时候就直接复用这个空闲线程,这样就省去了创建.销毁线程损耗.当然空闲线程也会是一种资源的浪费(所有才有空闲线程存活时间的限制),但总比频繁的创建销毁线程好太多. 下面是我的测试代码 /* * @TODO 线程池测试 */ @

  • 详谈Java几种线程池类型介绍及使用方法

    一.线程池使用场景 •单个任务处理时间短 •将需处理的任务数量大 二.使用Java线程池好处 1.使用new Thread()创建线程的弊端: •每次通过new Thread()创建对象性能不佳. •线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom. •缺乏更多功能,如定时执行.定期执行.线程中断. 2.使用Java线程池的好处: •重用存在的线程,减少对象创建.消亡的开销,提升性能. •可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞

  • Java 线程池ExecutorService详解及实例代码

    Java 线程池ExecutorService 1.线程池 1.1什么情况下使用线程池 单个任务处理的时间比较短. 将需处理的任务的数量大. 1.2使用线程池的好处 减少在创建和销毁线程上所花的时间以及系统资源的开销. 如果不使用线程池,有可能造成系统创建大量线程而导致消耗系统内存以及"过度切换"; 2.ExecutorService和Executors 2.1简介 ExecutorService是一个接口,继承了Executor, public interface ExecutorS

  • 深入java线程池的使用详解

    在Java 5.0之前启动一个任务是通过调用Thread类的start()方法来实现的,任务的提于交和执行是同时进行的,如果你想对任务的执行进行调度或是控制 同时执行的线程数量就需要额外编写代码来完成.5.0里提供了一个新的任务执行架构使你可以轻松地调度和控制任务的执行,并且可以建立一个类似数据库连接 池的线程池来执行任务.这个架构主要有三个接口和其相应的具体类组成.这三个接口是Executor, ExecutorService.ScheduledExecutorService,让我们先用一个图

  • 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } } ).start(); 那你就out太多了,new Thread的弊端如下: a. 每次new Thread新建对象性能差. b. 线程缺乏统一管理,可能无限

  • Java 线程池详解及实例代码

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收. 所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因. 例如Android中常见到的很多通用组件一般都离不开"池"的概念,如各种图片

  • Java线程池的几种实现方法和区别介绍

    Java线程池的几种实现方法和区别介绍 import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.E

  • java中通用的线程池实例代码

    复制代码 代码如下: package com.smart.frame.task.autoTask; import java.util.Collection;import java.util.Vector; /** * 任务分发器 */public class TaskManage extends Thread{    protected Vector<Runnable> tasks = new Vector<Runnable>();    protected boolean run

  • 支持生产阻塞的Java线程池

    通常来说,生产任务的速度要大于消费的速度.一个细节问题是,队列长度,以及如何匹配生产和消费的速度. 一个典型的生产者-消费者模型如下:   在并发环境下利用J.U.C提供的Queue实现可以很方便地保证生产和消费过程中的线程安全.这里需要注意的是,Queue必须设置初始容量,防止生产者生产过快导致队列长度暴涨,最终触发OutOfMemory. 对于一般的生产快于消费的情况.当队列已满时,我们并不希望有任何任务被忽略或得不到执行,此时生产者可以等待片刻再提交任务,更好的做法是,把生产者阻塞在提交任

  • Java代码构建一个线程池

    在现代的操作系统中,有一个很重要的概念――线程,几乎所有目前流行的操作系统都支持线程,线程来源于操作系统中进程的概念,进程有自己的虚拟地址空间以及正文段.数据段及堆栈,而且各自占有不同的系统资源(例如文件.环境变量等等).与此不同,线程不能单独存在,它依附于进程,只能由进程派生.如果一个进程派生出了两个线程,那这两个线程共享此进程的全局变量和代码段,但每个线程各拥有各自的堆栈,因此它们拥有各自的局部变量,线程在UNIX系统中还被进一步分为用户级线程(由进程自已来管理)和系统级线程(由操作系统的调

随机推荐