• Two-Phase Termination Design Pattern


    分两个阶段结束线程

    第一阶段:结束线程
    第二阶段:清理释放资源

    简单版

    package com.dwz.concurrency2.chapter17;
    
    import java.util.Random;
    
    public class CounterIncrement extends Thread {
        
        private volatile boolean terminated = false;
        
        private int counter = 0;
        
        private Random random = new Random(System.currentTimeMillis());
        
        @Override
        public void run() {
            try {
                while (!terminated) {
                    System.out.println(Thread.currentThread().getName() + " " + counter++);
                    Thread.sleep(random.nextInt(1000));
                } 
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                this.clean();
            }
        }
        
        private void clean() {
            System.out.println("do some clean work for the second phase, current counter is " + counter);
        }
        
        public void close() {
            this.terminated = true;
            this.interrupt();
        }
    }

    测试

    package com.dwz.concurrency2.chapter17;
    
    public class CounterTest {
        public static void main(String[] args) throws InterruptedException {
            CounterIncrement counterIncrement = new CounterIncrement();
            counterIncrement.start();
            
            Thread.sleep(10_000L);
            counterIncrement.close();
        }
    }

    改进版

    AppServer服务器

    package com.dwz.concurrency2.chapter17;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class AppServer extends Thread {
        private final int port;
        
        private static final int DEFAULT_PORT = 12722;
        
        private volatile boolean start = true;
        
        private List<ClientHandler> clientHandlers = new ArrayList<>();
        
        private final ExecutorService executor = Executors.newFixedThreadPool(10);
        
        private ServerSocket server;
        
        public AppServer() {
            this(DEFAULT_PORT);
        }
        
        public AppServer(int port) {
            this.port = port;
        }
        
        @Override
        public void run() {
            try {
                this.server = new ServerSocket(port);
                while (start) {
                    Socket client = server.accept();
                    ClientHandler clientHandler = new ClientHandler(client);
                    executor.submit(clientHandler);
                    this.clientHandlers.add(clientHandler);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                this.dispose();
            }
        }
        
        private void dispose() {
            this.clientHandlers.stream().forEach(ClientHandler::stop);
            this.executor.shutdown();
        }
    
        public void shotdown() throws IOException {
            this.start = false;
            this.interrupt();
            this.server.close();
        }
    }

    ClientHandler控制器

    package com.dwz.concurrency2.chapter17;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    public class ClientHandler implements Runnable {
        private final Socket socket;
        
        private volatile boolean running = true;
    
        public ClientHandler(Socket socket) {
            this.socket = socket;
        }
        
        @Override
        public void run() {
            //将需要关闭的资源放到try(){}的()中会主动帮我们释放资源,@since jdk1.7
            try (InputStream inputstream = socket.getInputStream();
                 OutputStream outputstream = socket.getOutputStream();
                 BufferedReader br = new BufferedReader(new InputStreamReader(inputstream));
                 PrintWriter printWriter = new PrintWriter(outputstream)) {
                while (running) {
                    String message = br.readLine();
                    if(null == message) {
                        break;
                    }
                    System.out.println("Come from client ->" + message);
                    printWriter.write("echo dang->" + message + "
    ");
                    printWriter.flush();
                }
            } catch (IOException e) {
                this.running = false;
            } finally {
                this.stop();
            }
        }
        
        public void stop() {
            if(!running) {
                return;
            }
            
            this.running = false;
            try {
                this.socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    测试步骤:

    1.启动AppServer 

    2.在cmd中输入指令 telnet localhost port连上服务器发送消息

    package com.dwz.concurrency2.chapter17;
    
    import java.io.IOException;
    
    public class AppServerClient {
        public static void main(String[] args) throws InterruptedException, IOException {
            AppServer appServer = new AppServer(13345);
            appServer.start();
            
            Thread.sleep(20_000L);
            appServer.shotdown();
        }
    }
  • 相关阅读:
    那些年读过的书《Java并发编程实战》和《Java并发编程的艺术》三、任务执行框架—Executor框架小结
    那些年读过的书《Java并发编程实战》二、如何设计线程安全类
    那些年读过的书《Java并发编程实战》一、构建线程安全类和并发应用程序的基础
    重读《深入理解Java虚拟机》七、探究Java内存模型
    重读《深入理解Java虚拟机》六、Java泛型 VS C#泛型 (伪泛型 VS 真泛型)
    重读《深入理解Java虚拟机》五、虚拟机如何执行字节码?程序方法如何被执行?虚拟机执行引擎的工作机制
    重读《深入理解Java虚拟机》四、虚拟机如何加载Class文件
    input 文本框禁止输入表情
    win7右下角无线网图标显示未连接,但是实际上已连接上,也能上网
    history.back(-1)和history.go(-1)的区别
  • 原文地址:https://www.cnblogs.com/zheaven/p/12167191.html
Copyright © 2020-2023  润新知