Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package rb.test;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.ScheduledThreadPoolExecutor;
- import java.util.concurrent.ThreadFactory;
- import java.util.concurrent.TimeUnit;
- public class ShutdownDilemma {
- private static Manager m2;
- /**
- * this is implementation code, I can't control
- */
- public static void main(String[] args) throws Exception {
- // Pitfall Nr. 1:
- // the reference to the manager is not kept. If calling close at the
- // finalize method (triggered by gc), the updater for the service won't
- // run as it should
- Service service1 = new Callable<Service>() {
- @Override
- public Service call() throws Exception {
- return new Manager("1").createService();
- }
- }.call();
- System.gc(); // after some time the gc runs
- // Pitfall Nr. 2:
- // the reference is kept, but the close method is not called when jvm
- // should be stopped.
- m2 = new Manager("2");
- Service service2 = m2.createService();
- for (int i = 0; i < 10; i++) {
- service1.doSomething();
- service2.doSomething();
- }
- System.out.println("jvm should shutdown now");
- }
- /** below are the classes of "my library" **/
- static class Manager implements AutoCloseable {
- private final List<Updater> updaters = new LinkedList<>();
- private final ScheduledExecutorService executor;
- private final String name;
- public Manager(String index) {
- name = index;
- executor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = new Thread(r, "Updater-Thread-"+index);
- thread.setDaemon(true);
- return thread;
- }
- });
- }
- Service createService() {
- Service s = new Service(name);
- Updater u = new Updater(s, name);
- executor.scheduleWithFixedDelay(u, 0, 5000, TimeUnit.SECONDS);
- updaters.add(u);
- System.out.println("manager"+name+"::createService");
- return s;
- }
- @Override
- public void close() throws Exception {
- updaters.forEach(u -> u.close());
- executor.shutdown();
- }
- }
- static class Service {
- private volatile String data;
- private String name;
- public Service(String name) {
- this.name = "service"+name;
- }
- public int doSomething() {
- System.out.println(name+"::doSomething");
- return data == null ? -1 : data.length();
- }
- public void setData(String data) {
- this.data = data;
- }
- }
- static class Updater implements Runnable, AutoCloseable {
- private Service service;
- private ThirdPartyConnection connection;
- private String name;
- public Updater(Service s, String name) {
- service = s;
- connection = new ThirdPartyConnection();
- connection.connect();
- this.name = "updater"+name;
- }
- @Override
- public void run() {
- System.out.println(name+"::run");
- service.setData(connection.getData());
- }
- @Override
- public void close() {
- try {
- connection.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * a class from a third party library I can't control
- */
- static class ThirdPartyConnection implements AutoCloseable {
- Thread t = new Thread(new Runnable() {
- @Override
- public void run() {
- while (true) {
- // does something
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- break;
- }
- }
- }
- }, "Connection-Thread");
- public void connect() {
- t.start();
- }
- public String getData() {
- // uses the thread in some way to transfer data
- return "";
- }
- @Override
- public void close() throws Exception {
- t.interrupt();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment