Guest User

ShutdownDilemma.java

a guest
Nov 14th, 2017
315
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 3.74 KB | None | 0 0
  1. package rb.test;
  2.  
  3. import java.util.LinkedList;
  4. import java.util.List;
  5. import java.util.concurrent.Callable;
  6. import java.util.concurrent.ScheduledExecutorService;
  7. import java.util.concurrent.ScheduledThreadPoolExecutor;
  8. import java.util.concurrent.ThreadFactory;
  9. import java.util.concurrent.TimeUnit;
  10.  
  11. public class ShutdownDilemma {
  12.  
  13.     private static Manager m2;
  14.  
  15.     /**
  16.      * this is implementation code, I can't control
  17.      */
  18.     public static void main(String[] args) throws Exception {
  19.         // Pitfall Nr. 1:
  20.         // the reference to the manager is not kept. If calling close at the
  21.         // finalize method (triggered by gc), the updater for the service won't
  22.         // run as it should
  23.         Service service1 = new Callable<Service>() {
  24.  
  25.             @Override
  26.             public Service call() throws Exception {
  27.                 return new Manager("1").createService();
  28.             }
  29.         }.call();
  30.         System.gc(); // after some time the gc runs
  31.  
  32.         // Pitfall Nr. 2:
  33.         // the reference is kept, but the close method is not called when jvm
  34.         // should be stopped.
  35.         m2 = new Manager("2");
  36.         Service service2 = m2.createService();
  37.        
  38.         for (int i = 0; i < 10; i++) {
  39.             service1.doSomething();
  40.             service2.doSomething();
  41.         }
  42.  
  43.         System.out.println("jvm should shutdown now");
  44.     }
  45.  
  46.     /** below are the classes of "my library" **/
  47.  
  48.     static class Manager implements AutoCloseable {
  49.  
  50.         private final List<Updater> updaters = new LinkedList<>();
  51.         private final ScheduledExecutorService executor;
  52.         private final String name;
  53.  
  54.         public Manager(String index) {
  55.             name = index;
  56.             executor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
  57.  
  58.                 @Override
  59.                 public Thread newThread(Runnable r) {
  60.                     Thread thread = new Thread(r, "Updater-Thread-"+index);
  61.                     thread.setDaemon(true);
  62.                     return thread;
  63.                 }
  64.             });
  65.         }
  66.  
  67.         Service createService() {
  68.             Service s = new Service(name);
  69.             Updater u = new Updater(s, name);
  70.             executor.scheduleWithFixedDelay(u, 0, 5000, TimeUnit.SECONDS);
  71.             updaters.add(u);
  72.             System.out.println("manager"+name+"::createService");
  73.             return s;
  74.         }
  75.  
  76.         @Override
  77.         public void close() throws Exception {
  78.             updaters.forEach(u -> u.close());
  79.             executor.shutdown();
  80.         }
  81.  
  82.     }
  83.  
  84.     static class Service {
  85.  
  86.         private volatile String data;
  87.         private String name;
  88.  
  89.         public Service(String name) {
  90.             this.name = "service"+name;
  91.         }
  92.  
  93.         public int doSomething() {
  94.             System.out.println(name+"::doSomething");
  95.             return data == null ? -1 : data.length();
  96.         }
  97.  
  98.         public void setData(String data) {
  99.             this.data = data;
  100.         }
  101.  
  102.     }
  103.  
  104.     static class Updater implements Runnable, AutoCloseable {
  105.  
  106.         private Service service;
  107.         private ThirdPartyConnection connection;
  108.         private String name;
  109.  
  110.         public Updater(Service s, String name) {
  111.             service = s;
  112.             connection = new ThirdPartyConnection();
  113.             connection.connect();
  114.             this.name = "updater"+name;
  115.         }
  116.  
  117.         @Override
  118.         public void run() {
  119.             System.out.println(name+"::run");
  120.             service.setData(connection.getData());
  121.         }
  122.  
  123.         @Override
  124.         public void close() {
  125.             try {
  126.                 connection.close();
  127.             } catch (Exception e) {
  128.                 e.printStackTrace();
  129.             }
  130.         }
  131.  
  132.     }
  133.  
  134.     /**
  135.      * a class from a third party library I can't control
  136.      */
  137.     static class ThirdPartyConnection implements AutoCloseable {
  138.  
  139.         Thread t = new Thread(new Runnable() {
  140.  
  141.             @Override
  142.             public void run() {
  143.                 while (true) {
  144.                     // does something
  145.                     try {
  146.                         Thread.sleep(500);
  147.                     } catch (InterruptedException e) {
  148.                         break;
  149.                     }
  150.                 }
  151.             }
  152.         }, "Connection-Thread");
  153.  
  154.         public void connect() {
  155.             t.start();
  156.         }
  157.  
  158.         public String getData() {
  159.             // uses the thread in some way to transfer data
  160.             return "";
  161.         }
  162.  
  163.         @Override
  164.         public void close() throws Exception {
  165.             t.interrupt();
  166.         }
  167.     }
  168. }
Advertisement
Add Comment
Please, Sign In to add comment