// Path: src/main/java/cn/xdean/jex/lang/collection/Wrapper.java
// public class Wrapper<T> {
// 
//   public static <T> Wrapper<T> of(T t) {
//     return new Wrapper<>(t);
//   }
// 
//   public static <T> Wrapper<T> empty() {
//     return Wrapper.of(null);
//   }
// 
//   private T value;
// 
//   public Wrapper(T value) {
//     super();
//     this.value = value;
//   }
// 
//   public T get() {
//     return value;
//   }
// 
//   public void set(T t) {
//     value = t;
//   }
// 
//   @Override
//   public int hashCode() {
//     return Objects.hash(value);
//   }
// 
//   @Override
//   public boolean equals(Object obj) {
//     if (this == obj) {
//       return true;
//     } else if (obj == null) {
//       return false;
//     } else if (!(obj instanceof Wrapper)) {
//       return false;
//     }
//     Wrapper<?> other = (Wrapper<?>) obj;
//     return Objects.equals(value, other.value);
//   }
// 
//   @Override
//   public String toString() {
//     return "Wrapper [value=" + value + "]";
//   }
// }
// 
// Path: src/main/java/cn/xdean/jex/lang/unsafe/FinalizeSupport.java
// public class FinalizeSupport {
// 
//   private static final Map<Reference<?>, Runnable> FINALIZE_TASK_MAP = new ConcurrentHashMap<>();
//   private static final ReferenceQueue<Object> QUEUE = new ReferenceQueue<>();
// 
//   static {
//     ThreadGroup tg = Thread.currentThread().getThreadGroup();
//     for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()) {
//     }
//     Thread handler = new FinalizeHandler(tg, "FinalizeSupport");
//     handler.setPriority(Thread.MAX_PRIORITY - 2);
//     handler.setDaemon(true);
//     handler.start();
//   }
// 
//   public static void finalize(Object o, Runnable r) {
//     finalize(o, r, Schedulers.io());
//   }
// 
//   public static void finalize(Object o, Runnable r, Scheduler s) {
//     FINALIZE_TASK_MAP.put(new PhantomReference<>(o, QUEUE), () -> s.createWorker().schedule(r));
//   }
// 
//   private static class FinalizeHandler extends Thread {
//     public FinalizeHandler(ThreadGroup tg, String name) {
//       super(tg, name);
//     }
// 
//     @Override
//     public void run() {
//       while (!Thread.interrupted()) {
//         try {
//           Reference<? extends Object> ref = QUEUE.remove();
//           if (ref != null) {
//             Optional.ofNullable(FINALIZE_TASK_MAP.remove(ref)).ifPresent(r -> r.run());
//           }
//         } catch (InterruptedException e) {
//           Thread.currentThread().interrupt();
//         }
//       }
//     }
//   }
// }


import cn.xdean.jex.lang.collection.Wrapper;
import cn.xdean.jex.lang.unsafe.FinalizeSupport;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
import org.junit.Test;
import java.lang.Thread.State;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;
package cn.xdean.jex.thrid.rxjava;




public class RxSchedulersTest {
  int hitCount;

  @Test
  public void testGC() throws Exception {
    CountDownLatch done = new CountDownLatch(1);
    Scheduler scheduler = RxSchedulers.fixedSize(1);
    FinalizeSupport.finalize(scheduler, done::countDown);
    Wrapper<Thread> worker = Wrapper.empty();
    Observable.just(1)
        .subscribeOn(scheduler)
        .doOnNext(i -> worker.set(Thread.currentThread()))
        .blockingSubscribe();
    scheduler = null;
    for (int i = 0; i < 10; i++) {
      Thread.sleep(10);
// Path: src/main/java/cn/xdean/jex/lang/collection/Wrapper.java
// public class Wrapper<T> {
// 
//   public static <T> Wrapper<T> of(T t) {
//     return new Wrapper<>(t);
//   }
// 
//   public static <T> Wrapper<T> empty() {
//     return Wrapper.of(null);
//   }
// 
//   private T value;
// 
//   public Wrapper(T value) {
//     super();
//     this.value = value;
//   }
// 
//   public T get() {
//     return value;
//   }
// 
//   public void set(T t) {
//     value = t;
//   }
// 
//   @Override
//   public int hashCode() {
//     return Objects.hash(value);
//   }
// 
//   @Override
//   public boolean equals(Object obj) {
//     if (this == obj) {
//       return true;
//     } else if (obj == null) {
//       return false;
//     } else if (!(obj instanceof Wrapper)) {
//       return false;
//     }
//     Wrapper<?> other = (Wrapper<?>) obj;
//     return Objects.equals(value, other.value);
//   }
// 
//   @Override
//   public String toString() {
//     return "Wrapper [value=" + value + "]";
//   }
// }
// 
// Path: src/main/java/cn/xdean/jex/lang/unsafe/FinalizeSupport.java
// public class FinalizeSupport {
// 
//   private static final Map<Reference<?>, Runnable> FINALIZE_TASK_MAP = new ConcurrentHashMap<>();
//   private static final ReferenceQueue<Object> QUEUE = new ReferenceQueue<>();
// 
//   static {
//     ThreadGroup tg = Thread.currentThread().getThreadGroup();
//     for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()) {
//     }
//     Thread handler = new FinalizeHandler(tg, "FinalizeSupport");
//     handler.setPriority(Thread.MAX_PRIORITY - 2);
//     handler.setDaemon(true);
//     handler.start();
//   }
// 
//   public static void finalize(Object o, Runnable r) {
//     finalize(o, r, Schedulers.io());
//   }
// 
//   public static void finalize(Object o, Runnable r, Scheduler s) {
//     FINALIZE_TASK_MAP.put(new PhantomReference<>(o, QUEUE), () -> s.createWorker().schedule(r));
//   }
// 
//   private static class FinalizeHandler extends Thread {
//     public FinalizeHandler(ThreadGroup tg, String name) {
//       super(tg, name);
//     }
// 
//     @Override
//     public void run() {
//       while (!Thread.interrupted()) {
//         try {
//           Reference<? extends Object> ref = QUEUE.remove();
//           if (ref != null) {
//             Optional.ofNullable(FINALIZE_TASK_MAP.remove(ref)).ifPresent(r -> r.run());
//           }
//         } catch (InterruptedException e) {
//           Thread.currentThread().interrupt();
//         }
//       }
//     }
//   }
// }


// Path: src/test/java/cn/xdean/jex/thrid/rxjava/RxSchedulersTest.java
import cn.xdean.jex.lang.collection.Wrapper;
import cn.xdean.jex.lang.unsafe.FinalizeSupport;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
import org.junit.Test;
import java.lang.Thread.State;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.*;

package cn.xdean.jex.thrid.rxjava;




public class RxSchedulersTest {
  int hitCount;

  @Test
  public void testGC() throws Exception {
    CountDownLatch done = new CountDownLatch(1);
    Scheduler scheduler = RxSchedulers.fixedSize(1);
    FinalizeSupport.finalize(scheduler, done::countDown);
    Wrapper<Thread> worker = Wrapper.empty();
    Observable.just(1)
        .subscribeOn(scheduler)
        .doOnNext(i -> worker.set(Thread.currentThread()))
        .blockingSubscribe();
    scheduler = null;
    for (int i = 0; i < 10; i++) {
      Thread.sleep(10);
      System.gc();