reactor和thread线程_reactor模式:多线程的reactor模式

单线程的reactor模式并没有解决IO和CPU处理速度不匹配问题,所以多线程的reactor模式引入线程池的概念,把耗时的IO操作交由线程池处理,处理完了之后再同步到selectionkey中,服务器架构图如下

上文(reactor模式:单线程的reactor模式)提到,以read和send阶段IO最为频繁,所以多线程的reactor版本里,把这2个阶段单独拎出来。

下面看看代码实现

1 //Reactor線程 (该类与单线程的处理基本无变动)

2 packageserver;3

4 importjava.io.IOException;5 importjava.net.InetSocketAddress;6 importjava.nio.channels.SelectionKey;7 importjava.nio.channels.Selector;8 importjava.nio.channels.ServerSocketChannel;9 importjava.util.Iterator;10 importjava.util.Set;11

12 public class TCPReactor implementsRunnable {13

14 private finalServerSocketChannel ssc;15 private finalSelector selector;16

17 public TCPReactor(int port) throwsIOException {18 selector =Selector.open();19 ssc =ServerSocketChannel.open();20 InetSocketAddress addr = newInetSocketAddress(port);21 ssc.socket().bind(addr); //在ServerSocketChannel綁定監聽端口

22 ssc.configureBlocking(false); //設置ServerSocketChannel為非阻塞

23 SelectionKey sk = ssc.register(selector, SelectionKey.OP_ACCEPT); //ServerSocketChannel向selector註冊一個OP_ACCEPT事件,然後返回該通道的key

24 sk.attach(new Acceptor(selector, ssc)); //給定key一個附加的Acceptor對象

25 }26

27 @Override28 public voidrun() {29 while (!Thread.interrupted()) { //在線程被中斷前持續運行

30 System.out.println("Waiting for new event on port: " + ssc.socket().getLocalPort() + "...");31 try{32 if (selector.select() == 0) //若沒有事件就緒則不往下執行

33 continue;34 } catch(IOException e) {35 //TODO Auto-generated catch block

36 e.printStackTrace();37 }38 Set selectedKeys = selector.selectedKeys(); //取得所有已就緒事件的key集合

39 Iterator it =selectedKeys.iterator();40 while(it.hasNext()) {41 dispatch((SelectionKey) (it.next())); //根據事件的key進行調度

42 it.remove();43 }44 }45 }46

47 /*

48 * name: dispatch(SelectionKey key)49 * description: 調度方法,根據事件綁定的對象開新線程50 */

51 private voiddispatch(SelectionKey key) {52 Runnable r = (Runnable) (key.attachment()); //根據事件之key綁定的對象開新線程

53 if (r != null)54 r.run();55 }56

57 }

1 //接受連線請求線程

2 packageserver;3

4 importjava.io.IOException;5 importjava.nio.channels.SelectionKey;6 importjava.nio.channels.Selector;7 importjava.nio.channels.ServerSocketChannel;8 importjava.nio.channels.SocketChannel;9

10 public class Acceptor implementsRunnable {11

12 private finalServerSocketChannel ssc;13 private finalSelector selector;14

15 publicAcceptor(Selector selector, ServerSocketChannel ssc) {16 this.ssc=ssc;17 this.selector=selector;18 }19

20 @Override21 public voidrun() {22 try{23 SocketChannel sc= ssc.accept(); //接受client連線請求

24 System.out.println(sc.socket().getRemoteSocketAddress().toString() + " is connected.");25

26 if(sc!=null) {27 sc.configureBlocking(false); //設置為非阻塞

28 SelectionKey sk = sc.register(selector, SelectionKey.OP_READ); //SocketChannel向selector註冊一個OP_READ事件,然後返回該通道的key

29 selector.wakeup(); //使一個阻塞住的selector操作立即返回

30 sk.attach(new TCPHandler(sk, sc)); //給定key一個附加的TCPHandler對象

31 }32

33 } catch(IOException e) {34 //TODO Auto-generated catch block

35 e.printStackTrace();36 }37 }38

39

40 }

1 //Handler線程

2 packageserver;3

4 importjava.io.IOException;5 importjava.nio.channels.SelectionKey;6 importjava.nio.channels.SocketChannel;7 importjava.util.concurrent.LinkedBlockingQueue;8 importjava.util.concurrent.ThreadPoolExecutor;9 importjava.util.concurrent.TimeUnit;10

11 public class TCPHandler implementsRunnable {12

13 private finalSelectionKey sk;14 private finalSocketChannel sc;15 private static final int THREAD_COUNTING = 10;16 private static ThreadPoolExecutor pool = newThreadPoolExecutor(17 THREAD_COUNTING, THREAD_COUNTING, 10, TimeUnit.SECONDS,18 new LinkedBlockingQueue()); //線程池

19

20 HandlerState state; //以狀態模式實現Handler

21

22 publicTCPHandler(SelectionKey sk, SocketChannel sc) {23 this.sk =sk;24 this.sc =sc;25 state = new ReadState(); //初始狀態設定為READING

26 pool.setMaximumPoolSize(32); //設置線程池最大線程數

27 }28

29 @Override30 public voidrun() {31 try{32 state.handle(this, sk, sc, pool);33

34 } catch(IOException e) {35 System.out.println("[Warning!] A client has been closed.");36 closeChannel();37 }38 }39

40 public voidcloseChannel() {41 try{42 sk.cancel();43 sc.close();44 } catch(IOException e1) {45 e1.printStackTrace();46 }47 }48

49 public voidsetState(HandlerState state) {50 this.state =state;51 }52 }53

54

1 packageserver;2

3 importjava.io.IOException;4 importjava.nio.channels.SelectionKey;5 importjava.nio.channels.SocketChannel;6 importjava.util.concurrent.ThreadPoolExecutor;7

8 public interfaceHandlerState {9

10 public voidchangeState(TCPHandler h);11

12 public voidhandle(TCPHandler h, SelectionKey sk, SocketChannel sc,13 ThreadPoolExecutor pool) throwsIOException ;14 }

1 packageserver;2

3 importjava.io.IOException;4 importjava.nio.ByteBuffer;5 importjava.nio.channels.SelectionKey;6 importjava.nio.channels.SocketChannel;7 importjava.util.concurrent.ThreadPoolExecutor;8

9 public class ReadState implementsHandlerState{10

11 privateSelectionKey sk;12

13 publicReadState() {14 }15

16 @Override17 public voidchangeState(TCPHandler h) {18 //TODO Auto-generated method stub

19 h.setState(newWorkState());20 }21

22 @Override23 public voidhandle(TCPHandler h, SelectionKey sk, SocketChannel sc,24 ThreadPoolExecutor pool) throws IOException { //read()

25 this.sk =sk;26 //non-blocking下不可用Readers,因為Readers不支援non-blocking

27 byte[] arr = new byte[1024];28 ByteBuffer buf =ByteBuffer.wrap(arr);29

30 int numBytes = sc.read(buf); //讀取字符串

31 if(numBytes == -1)32 {33 System.out.println("[Warning!] A client has been closed.");34 h.closeChannel();35 return;36 }37 String str = new String(arr); //將讀取到的byte內容轉為字符串型態

38 if ((str != null) && !str.equals(" ")) {39 h.setState(new WorkState()); //改變狀態(READING->WORKING)

40 pool.execute(new WorkerThread(h, str)); //do process in worker thread

41 System.out.println(sc.socket().getRemoteSocketAddress().toString()42 + " > " +str);43 }44

45 }46

47 /*

48 * 執行邏輯處理之函數49 */

50 synchronized voidprocess(TCPHandler h, String str) {51 //do process(decode, logically process, encode)..52 //..

53 h.setState(new WriteState()); //改變狀態(WORKING->SENDING)

54 this.sk.interestOps(SelectionKey.OP_WRITE); //通過key改變通道註冊的事件

55 this.sk.selector().wakeup(); //使一個阻塞住的selector操作立即返回

56 }57

58 /*

59 * 工作者線程60 */

61 class WorkerThread implementsRunnable {62

63 TCPHandler h;64 String str;65

66 publicWorkerThread(TCPHandler h, String str) {67 this.h =h;68 this.str=str;69 }70

71 @Override72 public voidrun() {73 process(h, str);74 }75

76 }77 }

1 packageserver;2

3 importjava.io.IOException;4 importjava.nio.channels.SelectionKey;5 importjava.nio.channels.SocketChannel;6 importjava.util.concurrent.ThreadPoolExecutor;7

8 public class WorkState implementsHandlerState {9

10 publicWorkState() {11 }12

13 @Override14 public voidchangeState(TCPHandler h) {15 //TODO Auto-generated method stub

16 h.setState(newWriteState());17 }18

19 @Override20 public voidhandle(TCPHandler h, SelectionKey sk, SocketChannel sc,21 ThreadPoolExecutor pool) throwsIOException {22 //TODO Auto-generated method stub

23

24 }25

26 }

1 packageserver;2

3 importjava.io.IOException;4 importjava.nio.ByteBuffer;5 importjava.nio.channels.SelectionKey;6 importjava.nio.channels.SocketChannel;7 importjava.util.concurrent.ThreadPoolExecutor;8

9 public class WriteState implementsHandlerState{10

11 publicWriteState() {12 }13

14 @Override15 public voidchangeState(TCPHandler h) {16 //TODO Auto-generated method stub

17 h.setState(newReadState());18 }19

20 @Override21 public voidhandle(TCPHandler h, SelectionKey sk, SocketChannel sc,22 ThreadPoolExecutor pool) throws IOException { //send()23 //get message from message queue

24

25 String str = "Your message has sent to "

26 + sc.socket().getLocalSocketAddress().toString() + "\r\n";27 ByteBuffer buf = ByteBuffer.wrap(str.getBytes()); //wrap自動把buf的position設為0,所以不需要再flip()

28

29 while(buf.hasRemaining()) {30 sc.write(buf); //回傳給client回應字符串,發送buf的position位置 到limit位置為止之間的內容

31 }32

33 h.setState(new ReadState()); //改變狀態(SENDING->READING)

34 sk.interestOps(SelectionKey.OP_READ); //通過key改變通道註冊的事件

35 sk.selector().wakeup(); //使一個阻塞住的selector操作立即返回

36 }37 }

1 packageserver;2

3 importjava.io.IOException;4

5 public classMain {6

7

8 public static voidmain(String[] args) {9 //TODO Auto-generated method stub

10 try{11 TCPReactor reactor = new TCPReactor(1333);12 reactor.run();13 } catch(IOException e) {14 //TODO Auto-generated catch block

15 e.printStackTrace();16 }17 }18

19 }

总的来说,多线程版本的reactor是为了解决单线程reactor版本的IO和CPU处理速度不匹配问题,从而达到高效处理的目的

参考文章:

https://blog.csdn.net/yehjordan/article/details/51017025

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值