本章主要介绍Socket的基本概念,传统的同步阻塞式I/O编程,伪异步IO实现,学习NIO的同步非阻塞编程和NIO2.0(AIO)异步非阻塞编程。

  

目前为止,Java共支持3种网络编程模型:BIO、NIO、AIO:

Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。 BIO、NIO、AIO适用场景分析: BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
 

  一:基本概念

        Socket又被称为 "套接字" ,应用程序通常都是通过 "套接字" 向网络发出请求和接收请求。Socket和serverSocket类位于java.net包中。ServerSocket用于(Server)服务端,Socket用于

      (Client)客户端。当服务端和客户端建立连接后。两端都会产生一个Socket实例,并且是平等的。不管是Socket还是ServerSocket。都是通过操作SocketImpl和其子类完成相关功能。

 

    

    连接过程四步骤: 1:服务器监听  2:客户端请求   3:服务端连接确认   4:客户端连接确认

  二:传统同步阻塞IO实现

           服务端ServerSocket:

             

1               final static int PROT = 8765;
2
3               ServerSocket server = null;
4
5               server = new ServerSocket(PROT);
6
7               Socket socket = server.accept(); //进行阻塞
8
9               new Thread(new ServerHandler(socket)).start(); //服务端运行,等待客户端连接

         客户端Socket:

              

1               final static String ADDRESS = "127.0.0.1";
2
3               final static int PORT = 8765;
4
5                Socket socket = null;
6
7               socket = new Socket(ADDRESS, PORT); //进行连接

      

          服务端处理器ServerHandler:

          

 1              // 实现Runnable
2
3                 private Socket socket ;
4
5                 public ServerHandler(Socket socket){
6                   this.socket = socket;
7                 }
8
9               //重写run方法:   
10
11                 @Override
12                 public void run() {
13                 BufferedReader in = null;
14                 PrintWriter out = null;
15                   try {
16                     in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
17                     out = new PrintWriter(this.socket.getOutputStream(), true);
18                     String body = null;
19                       while(true){
20                         body = in.readLine();
21                           if(body == null) break;
22                             System.out.println("Server :" + body);
23                             out.println("服务器端回送响的应数据.");
24                     }
25                     } catch (Exception e) {
26                       e.printStackTrace();
27
28                     }

  

  三:伪异步实现:

      原理:传统的是直接new Thread()来进行运行任务,现在我们直接通过自定义线程池来实现伪异步。

       

1           //之前服务端运行:   
2
3           //新建一个线程执行客户端的任务
4           new Thread(new ServerHandler(socket)).start();

     

1           // 现在伪异步:
2
3           HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 1000);
4             while(true){
5               socket = server.accept();
6               executorPool.execute(new ServerHandler(socket));
7             }

      自定义线程池:HandlerExecutorPool

         

 1          public class HandlerExecutorPool {
2
3             private ExecutorService executor;
4             public HandlerExecutorPool(int maxPoolSize, int queueSize){
5               this.executor = new ThreadPoolExecutor(
6               Runtime.getRuntime().availableProcessors(),
7               maxPoolSize,
8               120L,
9               TimeUnit.SECONDS,
10               new ArrayBlockingQueue<Runnable>(queueSize));
11               }
12
13             public void execute(Runnable task){
14               this.executor.execute(task);
15             }
16
17           }

  四:NIO(非阻塞编程)

        传统IO和NIO的差异:IO是同步阻塞   NIO是同步非阻塞。 在jdk1.7以后,NIO升级(NIO2.0)AIO,实现了异步非阻塞

        传统的IO(BIO)阻塞:在网络应用程序获取网络数据时,如果网络传输数据很慢,那么程序就一直等着,直到传输完毕为止。

        NIO:无需等待,直接获取数据,在数据没有传输完毕时,不获取数据,数据暂时放在缓冲区,等传输完毕以后,缓冲区发出通知,客户端获取数据,实现不等待。

        

       基本概念:

          Buffer(缓冲区)   channel(管道、通道) Selector(选择器,多路复用器)

          Buffer注意事项:每次在put(),for循环 之后都要进行flip()复位。要复位下标

          Buffer常用方法:

                flip()复位:因为buffer和游标类似,每次新增数据之后,它的下标都会自增,如果用for循环遍历时,他只会遍历没有填充的下标的值,所以要用filp()方法复

                      位。

                  wrap(数组):wrap方法会包裹一个数组: 一般这种用法不会先初始化缓存对象的长度,因为没有意义,最后还会被wrap所包裹的数组覆盖掉

                duplicate(): buffer复制的方法 。一个buffer数据复制给另外一个buffer数组

                position(index):设置buffer可读的下标的位置

                remaining() :返回buffer可读的长度

                get(数组):把buffer数据复制给数组

        

         Channel管道:双向

                两大类: 1:网络读写类(SelectableChannel)   2:文件操作类(FileChannel)

                    我们要使用的SocketChannel和ServerSocketChannel就在SelectableChannel类里面

         Selector:选择器(多路复用器)

                原理:Selector不断的注册轮询注册在其上的通道(SocketChannel),如果某一个通道发生了读写操作,这个通道就处于就绪状态,会被Selector轮询出

                     来。然后通过SelectionKey就可以获取到就绪的Channel集合,从而进行后续操作。

                四大状态:连接状态   阻塞状态   可读状态  可写状态

            

下面来看一下程序中是怎么通过这些类库实现Socket功能。

首先介绍一下几个辅助类

辅助类SerializableUtil,这个类用来把java对象序列化成字节数组,或者把字节数组反序列化成java对象。

[java] view plain copy

 

print?

  1. package com.googlecode.garbagecan.test.socket;
  2. import java.io.ByteArrayInputStream;
  3. import java.io.ByteArrayOutputStream;
  4. import java.io.IOException;
  5. import java.io.ObjectInputStream;
  6. import java.io.ObjectOutputStream;
  7. public class SerializableUtil {
  8. public static byte[] toBytes(Object object) {
  9. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  10. ObjectOutputStream oos = null;
  11. try {
  12. oos = new ObjectOutputStream(baos);
  13. oos.writeObject(object);
  14. byte[] bytes = baos.toByteArray();
  15. return bytes;
  16. } catch(IOException ex) {
  17. throw new RuntimeException(ex.getMessage(), ex);
  18. } finally {
  19. try {
  20. oos.close();
  21. } catch (Exception e) {}
  22. }
  23. }
  24. public static Object toObject(byte[] bytes) {
  25. ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
  26. ObjectInputStream ois = null;
  27. try {
  28. ois = new ObjectInputStream(bais);
  29. Object object = ois.readObject();
  30. return object;
  31. } catch(IOException ex) {
  32. throw new RuntimeException(ex.getMessage(), ex);
  33. } catch(ClassNotFoundException ex) {
  34. throw new RuntimeException(ex.getMessage(), ex);
  35. } finally {
  36. try {
  37. ois.close();
  38. } catch (Exception e) {}
  39. }
  40. }
  41. }

辅助类MyRequestObject和MyResponseObject,这两个类是普通的java对象,实现了Serializable接口。MyRequestObject类是Client发出的请求,MyResponseObject是Server端作出的响应。

[java] view plain copy

 

print?

  1. package com.googlecode.garbagecan.test.socket.nio;
  2. import java.io.Serializable;
  3. public class MyRequestObject implements Serializable {
  4. private static final long serialVersionUID = 1L;
  5. private String name;
  6. private String value;
  7. private byte[] bytes;
  8. public MyRequestObject(String name, String value) {
  9. this.name = name;
  10. this.value = value;
  11. this.bytes = new byte[1024];
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public String getValue() {
  20. return value;
  21. }
  22. public void setValue(String value) {
  23. this.value = value;
  24. }
  25. @Override
  26. public String toString() {
  27. StringBuffer sb = new StringBuffer();
  28. sb.append("Request [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");
  29. return sb.toString();
  30. }
  31. }
  32. package com.googlecode.garbagecan.test.socket.nio;
  33. import java.io.Serializable;
  34. public class MyResponseObject implements Serializable {
  35. private static final long serialVersionUID = 1L;
  36. private String name;
  37. private String value;
  38. private byte[] bytes;
  39. public MyResponseObject(String name, String value) {
  40. this.name = name;
  41. this.value = value;
  42. this.bytes = new byte[1024];
  43. }
  44. public String getName() {
  45. return name;
  46. }
  47. public void setName(String name) {
  48. this.name = name;
  49. }
  50. public String getValue() {
  51. return value;
  52. }
  53. public void setValue(String value) {
  54. this.value = value;
  55. }
  56. @Override
  57. public String toString() {
  58. StringBuffer sb = new StringBuffer();
  59. sb.append("Response [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");
  60. return sb.toString();
  61. }
  62. }

下面主要看一下Server端的代码,其中有一些英文注释对理解代码很有帮助,注释主要是来源jdk的文档和例子,这里就没有再翻译

[java] view plain copy

 

print?

  1. package com.googlecode.garbagecan.test.socket.nio;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.ClosedChannelException;
  7. import java.nio.channels.SelectionKey;
  8. import java.nio.channels.Selector;
  9. import java.nio.channels.ServerSocketChannel;
  10. import java.nio.channels.SocketChannel;
  11. import java.util.Iterator;
  12. import java.util.logging.Level;
  13. import java.util.logging.Logger;
  14. import com.googlecode.garbagecan.test.socket.SerializableUtil;
  15. public class MyServer3 {
  16. private final static Logger logger = Logger.getLogger(MyServer3.class.getName());
  17. public static void main(String[] args) {
  18. Selector selector = null;
  19. ServerSocketChannel serverSocketChannel = null;
  20. try {
  21. // Selector for incoming time requests
  22. selector = Selector.open();
  23. // Create a new server socket and set to non blocking mode
  24. serverSocketChannel = ServerSocketChannel.open();
  25. serverSocketChannel.configureBlocking(false);
  26. // Bind the server socket to the local host and port
  27. serverSocketChannel.socket().setReuseAddress(true);
  28. serverSocketChannel.socket().bind(new InetSocketAddress(10000));
  29. // Register accepts on the server socket with the selector. This
  30. // step tells the selector that the socket wants to be put on the
  31. // ready list when accept operations occur, so allowing multiplexed
  32. // non-blocking I/O to take place.
  33. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
  34. // Here's where everything happens. The select method will
  35. // return when any operations registered above have occurred, the
  36. // thread has been interrupted, etc.
  37. while (selector.select() > 0) {
  38. // Someone is ready for I/O, get the ready keys
  39. Iterator<SelectionKey> it = selector.selectedKeys().iterator();
  40. // Walk through the ready keys collection and process date requests.
  41. while (it.hasNext()) {
  42. SelectionKey readyKey = it.next();
  43. it.remove();
  44. // The key indexes into the selector so you
  45. // can retrieve the socket that's ready for I/O
  46. execute((ServerSocketChannel) readyKey.channel());
  47. }
  48. }
  49. } catch (ClosedChannelException ex) {
  50. logger.log(Level.SEVERE, null, ex);
  51. } catch (IOException ex) {
  52. logger.log(Level.SEVERE, null, ex);
  53. } finally {
  54. try {
  55. selector.close();
  56. } catch(Exception ex) {}
  57. try {
  58. serverSocketChannel.close();
  59. } catch(Exception ex) {}
  60. }
  61. }
  62. private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {
  63. SocketChannel socketChannel = null;
  64. try {
  65. socketChannel = serverSocketChannel.accept();
  66. MyRequestObject myRequestObject = receiveData(socketChannel);
  67. logger.log(Level.INFO, myRequestObject.toString());
  68. MyResponseObject myResponseObject = new MyResponseObject(
  69. "response for " + myRequestObject.getName(),
  70. "response for " + myRequestObject.getValue());
  71. sendData(socketChannel, myResponseObject);
  72. logger.log(Level.INFO, myResponseObject.toString());
  73. } finally {
  74. try {
  75. socketChannel.close();
  76. } catch(Exception ex) {}
  77. }
  78. }
  79. private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {
  80. MyRequestObject myRequestObject = null;
  81. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  82. ByteBuffer buffer = ByteBuffer.allocate(1024);
  83. try {
  84. byte[] bytes;
  85. int size = 0;
  86. while ((size = socketChannel.read(buffer)) >= 0) {
  87. buffer.flip();
  88. bytes = new byte[size];
  89. buffer.get(bytes);
  90. baos.write(bytes);
  91. buffer.clear();
  92. }
  93. bytes = baos.toByteArray();
  94. Object obj = SerializableUtil.toObject(bytes);
  95. myRequestObject = (MyRequestObject)obj;
  96. } finally {
  97. try {
  98. baos.close();
  99. } catch(Exception ex) {}
  100. }
  101. return myRequestObject;
  102. }
  103. private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {
  104. byte[] bytes = SerializableUtil.toBytes(myResponseObject);
  105. ByteBuffer buffer = ByteBuffer.wrap(bytes);
  106. socketChannel.write(buffer);
  107. }
  108. }

下面是Client的代码,代码比较简单就是启动了100个线程来访问Server

[java] view plain copy

 

print?

  1. package com.googlecode.garbagecan.test.socket.nio;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.net.SocketAddress;
  6. import java.nio.ByteBuffer;
  7. import java.nio.channels.SocketChannel;
  8. import java.util.logging.Level;
  9. import java.util.logging.Logger;
  10. import com.googlecode.garbagecan.test.socket.SerializableUtil;
  11. public class MyClient3 {
  12. private final static Logger logger = Logger.getLogger(MyClient3.class.getName());
  13. public static void main(String[] args) throws Exception {
  14. for (int i = 0; i < 100; i++) {
  15. final int idx = i;
  16. new Thread(new MyRunnable(idx)).start();
  17. }
  18. }
  19. private static final class MyRunnable implements Runnable {
  20. private final int idx;
  21. private MyRunnable(int idx) {
  22. this.idx = idx;
  23. }
  24. public void run() {
  25. SocketChannel socketChannel = null;
  26. try {
  27. socketChannel = SocketChannel.open();
  28. SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
  29. socketChannel.connect(socketAddress);
  30. MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);
  31. logger.log(Level.INFO, myRequestObject.toString());
  32. sendData(socketChannel, myRequestObject);
  33. MyResponseObject myResponseObject = receiveData(socketChannel);
  34. logger.log(Level.INFO, myResponseObject.toString());
  35. } catch (Exception ex) {
  36. logger.log(Level.SEVERE, null, ex);
  37. } finally {
  38. try {
  39. socketChannel.close();
  40. } catch(Exception ex) {}
  41. }
  42. }
  43. private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {
  44. byte[] bytes = SerializableUtil.toBytes(myRequestObject);
  45. ByteBuffer buffer = ByteBuffer.wrap(bytes);
  46. socketChannel.write(buffer);
  47. socketChannel.socket().shutdownOutput();
  48. }
  49. private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {
  50. MyResponseObject myResponseObject = null;
  51. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  52. try {
  53. ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
  54. byte[] bytes;
  55. int count = 0;
  56. while ((count = socketChannel.read(buffer)) >= 0) {
  57. buffer.flip();
  58. bytes = new byte[count];
  59. buffer.get(bytes);
  60. baos.write(bytes);
  61. buffer.clear();
  62. }
  63. bytes = baos.toByteArray();
  64. Object obj = SerializableUtil.toObject(bytes);
  65. myResponseObject = (MyResponseObject) obj;
  66. socketChannel.socket().shutdownInput();
  67. } finally {
  68. try {
  69. baos.close();
  70. } catch(Exception ex) {}
  71. }
  72. return myResponseObject;
  73. }
  74. }
  75. }
 

最后测试上面的代码,首先运行Server类,然后运行Client类,就可以分别在Server端和Client端控制台看到发送或接收到的MyRequestObject或MyResponseObject对象了。   

 

代码实现:

  注:转自http://blog.csdn.net/kongxx/article/details/7288896

    

  五:NIO2.0(AIO) 异步非阻塞

      AIO编程:在NIO基础上引入异步的通到的概念,实现了异步文件和异步套字节,jdk1.7以后升级。

    

        基本概念

          1 AsynchronousChannel:支持异步通道,包括服务端AsynchronousServerSocketChannel和客户端AsynchronousSocketChannel等实现。
          2 CompletionHandler:用户处理器。定义了一个用户处理就绪事件的接口,由用户自己实现,异步io的数据就绪后回调该处理器消费或处理数据。
          3 AsynchronousChannelGroup:一个用于资源共享的异步通道集合。处理IO事件和分配给CompletionHandler。(具体这块还没细看代码,后续再分析这块)

    

      所谓AIO,就是异步非阻塞IO,是NIO的升级版本,也就是NIO2.0版本,但是与NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可。这两种方法均为异步

        的,对于读操作而言,当有流可读取时,操作系统会将可读的流传入read方法的缓冲区,并通知应用程序;对于写操作而言,当操作系统将write方法传递的流写入完毕时,操作

        系统主动通知应用程序。 即可以理解为,read/write方法都是异步的,完成后会主动调用回调函数。

      具体代码实现:

           

 1            // Server类: 
2
3
4
5 /**
6 *
7 *类描述:AIO 服务端
8 *@author: 豪
9 *@date: 日期:2017-5-24 时间:上午10:48:12
10 *@version 1.0
11 */
12 public class Server {
13 //线程池
14 private ExecutorService executorService;
15 //线程组
16 private AsynchronousChannelGroup threadGroup;
17 //服务器通道
18 public AsynchronousServerSocketChannel assc;
19
20 public Server(int port){
21 try {
22 //创建一个缓存池
23 executorService = Executors.newCachedThreadPool();
24 //创建线程组
25 threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
26 //创建服务器通道
27 assc = AsynchronousServerSocketChannel.open(threadGroup);
28 //进行绑定
29 assc.bind(new InetSocketAddress(port));
30
31 System.out.println("server start , port : " + port);
32 //进行阻塞
33 assc.accept(this, new ServerCompletionHandler());
34 //一直阻塞 不让服务器停止
35 Thread.sleep(Integer.MAX_VALUE);
36
37 } catch (Exception e) {
38 e.printStackTrace();
39 }
40 }
41
42 public static void main(String[] args) {
43 Server server = new Server(8765);
44 }
45
46 }
 1 //ServerCompletionHandler类
2   
3
4 /**
5 *
6 *类描述:服务端处理类 所有的处理都在此类进行
7 *@author: 豪
8 *@date: 日期:2017-5-24 时间:上午10:47:45
9 *@version 1.0
10 */
11 public class ServerCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Server> {
12
13 @Override
14 public void completed(AsynchronousSocketChannel asc, Server attachment) {
15 //当有下一个客户端接入的时候 直接调用Server的accept方法,这样反复执行下去,保证多个客户端都可以阻塞
16 attachment.assc.accept(attachment, this);
17 read(asc);
18 }
19
20 private void read(final AsynchronousSocketChannel asc) {
21 //读取数据
22 ByteBuffer buf = ByteBuffer.allocate(1024);
23 asc.read(buf, buf, new CompletionHandler<Integer, ByteBuffer>() {
24 @Override
25 public void completed(Integer resultSize, ByteBuffer attachment) {
26 //进行读取之后,重置标识位
27 attachment.flip();
28 //获得读取的字节数
29 System.out.println("Server -> " + "收到客户端的数据长度为:" + resultSize);
30 //获取读取的数据
31 String resultData = new String(attachment.array()).trim();
32 System.out.println("Server -> " + "收到客户端的数据信息为:" + resultData);
33 String response = "服务器响应, 收到了客户端发来的数据: " + resultData;
34 write(asc, response);
35 }
36 @Override
37 public void failed(Throwable exc, ByteBuffer attachment) {
38 exc.printStackTrace();
39 }
40 });
41 }
42
43 private void write(AsynchronousSocketChannel asc, String response) {
44 try {
45 ByteBuffer buf = ByteBuffer.allocate(1024);
46 buf.put(response.getBytes());
47 buf.flip();
48 asc.write(buf).get();
49 } catch (InterruptedException e) {
50 e.printStackTrace();
51 } catch (ExecutionException e) {
52 e.printStackTrace();
53 }
54 }
55
56 @Override
57 public void failed(Throwable exc, Server attachment) {
58 exc.printStackTrace();
59 }
60
61 }
 1 //Clinet类:
2
3 /**
4 *
5 *类描述:AIO客户端
6 *@author: 豪
7 *@date: 日期:2017-5-24 时间:上午10:47:23
8 *@version 1.0
9 */
10 public class Client implements Runnable{
11
12 private AsynchronousSocketChannel asc ;
13
14 public Client() throws Exception {
15 asc = AsynchronousSocketChannel.open();
16 }
17
18 public void connect(){
19 asc.connect(new InetSocketAddress("127.0.0.1", 8765));
20 }
21
22 public void write(String request){
23 try {
24 asc.write(ByteBuffer.wrap(request.getBytes())).get();
25 read();
26 } catch (Exception e) {
27 e.printStackTrace();
28 }
29 }
30
31 private void read() {
32 ByteBuffer buf = ByteBuffer.allocate(1024);
33 try {
34 asc.read(buf).get();
35 buf.flip();
36 byte[] respByte = new byte[buf.remaining()];
37 buf.get(respByte);
38 System.out.println(new String(respByte,"utf-8").trim());
39 } catch (InterruptedException e) {
40 e.printStackTrace();
41 } catch (ExecutionException e) {
42 e.printStackTrace();
43 } catch (UnsupportedEncodingException e) {
44 e.printStackTrace();
45 }
46 }
47
48 @Override
49 public void run() {
50 while(true){
51
52 }
53 }
54
55 public static void main(String[] args) throws Exception {
56 Client c1 = new Client();
57 c1.connect();
58
59 Client c2 = new Client();
60 c2.connect();
61
62 Client c3 = new Client();
63 c3.connect();
64
65 new Thread(c1, "c1").start();
66 new Thread(c2, "c2").start();
67 new Thread(c3, "c3").start();
68
69 Thread.sleep(1000);
70
71 c1.write("c1 aaa");
72 c2.write("c2 bbbb");
73 c3.write("c3 ccccc");
74 }
75
76 }

   

            

java架构《Socket网络编程基础篇》的更多相关文章

  1. java架构《并发线程高级篇四》

    本章主要讲并发线程的常见的两种锁.重入锁和读写锁 一:重入锁(ReentrantLock) 概念:重入锁,在需要进行同步的代码加锁,但最后一定不要忘记释放锁,否则会造成锁永远不能释放,其他线程进不了 ...

  2. java架构《并发线程高级篇一》

    本章主要记录讲解并发线程的线程池.java.util.concurrent工具包里面的工具类. 一:Executor框架: Executors创建线程池的方法: newFixedThreadPool( ...

  3. java架构《并发线程高级篇二》

    本章主要记录讲解并发线程的线程池.使用Executor框架自定义线程池. 自定义线程池使用Queue队列所表示出来的形式: 1 ArrayBlockingQueue<Runnable>(3 ...

  4. java架构《并发线程高级篇三》

    本章主要介绍和讲解concurrent.util里面的常用的工具类. 一.CountDownLatch使用:(用于阻塞主线程) 应用场景 :通知线程休眠和运行的工具类,是wait和notify的升级版 ...

  5. Java高并发 -- 线程池

    Java高并发 -- 线程池 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 在使用线程池后,创建线程变成了从线程池里获得空闲线程,关闭线程变成了将线程归坏给线程池. ...

  6. Java高并发--线程安全策略

    Java高并发--线程安全策略 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 不可变对象 发布不可变对象可保证线程安全. 实现不可变对象有哪些要注意的地方?比如JDK ...

  7. Java并发-线程池篇-附场景分析

    作者:汤圆 个人博客:javalover.cc 前言 前面我们在创建线程时,都是直接new Thread(): 这样短期来看是没有问题的,但是一旦业务量增长,线程数过多,就有可能导致内存异常OOM,C ...

  8. Java高并发与多线程(四)-----锁

    今天,我们开始Java高并发与多线程的第四篇,锁. 之前的三篇,基本上都是在讲一些概念性和基础性的东西,东西有点零碎,但是像文科科目一样,记住就好了. 但是本篇是高并发里面真正的基石,需要大量的理解和 ...

  9. Java之创建线程的方式四:使用线程池

    import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.c ...

  10. java架构《并发线程中级篇》

    java多线程的三大设计模式 本章主要记录java常见的三大设计模式,Future.Master-Worker和生产者-消费者模式. 一.Future模式 使用场景:数据可以不及时返回,到下一次实际要 ...

随机推荐

  1. JS function 是函数也是对象, 浅谈原型链

    JS function 是函数也是对象, 浅谈原型链 JS 唯一支持的继承方式是通过原型链继承, 理解好原型链非常重要, 我记录下我的理解 1. 前言 new 出来的实例有 _proto_ 属性, 并 ...

  2. Above the Median

    http://www.forioi.com/p/3212 农夫约翰把他的N(1<=N<=1e5)奶牛排在一排来衡量他们的高度,牛i有:高度H_I(1<=H_I<=1e9)纳米– ...

  3. druid监控

    1 @ConfigurationProperties(prefix = "spring.datasource") 2 @Bean 3 public DataSource druid ...

  4. Java内存模型精讲

    1.JAVA 的并发模型 共享内存模型 在共享内存的并发模型里面,线程之间共享程序的公共状态,线程之间通过读写内存中公共状态来进行隐式通信 该内存指的是主内存,实际上是物理内存的一小部分 2.JAVA ...

  5. Kubernetes官方java客户端之六:OpenAPI基本操作

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. Linux 入门教程:基础操作 01

    1.1 实验内容 实验楼环境介绍 常用 Shell 命令及快捷键 Linux 使用小技巧 1.2 实验知识点 Linux 基本命令 通配符的使用 查看帮助文档 终端的概念 通常我们在使用 Linux ...

  7. Docker学习笔记之Dockerfile

    Dockerfile的编写格式为<命令><形式参数>,命令不区分大小写,但一般使用大写字母.Docker会依据Dockerfile文件中编写的命令顺序依次执行命令.Docker ...

  8. 【JS学习】String基础方法

    前言:本博客系列为学习后盾人js教程过程中的记录与产出,如果对你有帮助,欢迎关注,点赞,分享.不足之处也欢迎指正,作者会积极思考与改正. 目录 定义: 字符串的连接: 标签模板的使用: 字符串的基本方 ...

  9. Java中的NIO进阶

    目录 前言 NIO与多线程 Readable和Writeable的空触发 请求与返回的处理 事件的处理机制 NIO多线程使用的一个例子 前言 之前一篇文章简单介绍了NIO,并附了一个简单的例子,但是自 ...

  10. Docker 如何动态修改容器端口映射

    Docker端口映射往往是Docker Run命令时通过-p将容器内部端口映射到宿主机的指定端口上,一般来说容器的端口所对应的端口是提前确定需要映射的.但是有些情况下不得不需要临时映射端口,例如Doc ...