package xdean.jex.util.lang;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import xdean.jex.util.reflect.ReflectUtil;

public class FinalizeSupport {

  private static Map<Reference<?>, Runnable> map = new ConcurrentHashMap<>();
  private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
  private static Object lock;

  static {
    try {
      lock = ReflectUtil.getFieldValue(ReferenceQueue.class, queue, "lock");
    } catch (NoSuchFieldException e) {
      throw new Error("Can't find ReferenceQueue's lock, Check code and java version");
    }

    ThreadGroup tg = Thread.currentThread().getThreadGroup();
    for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()) {
      ;
    }
    Thread handler = new FinalizeHandler(tg, "Finalize Support");
    handler.setPriority(Thread.MAX_PRIORITY);
    handler.setDaemon(true);
    handler.start();
  }

  public static void finalize(Object o, Runnable r) {
    map.put(new PhantomReference<>(o, queue), r);
  }

  private static class FinalizeHandler extends Thread {
    public FinalizeHandler(ThreadGroup tg, String name) {
      super(tg, name);
    }

    @Override
    public void run() {
      synchronized (lock) {
        while (!Thread.interrupted()) {
          Reference<? extends Object> ref = queue.poll();
          if (ref == null) {
            try {
              lock.wait();
            } catch (InterruptedException e) {
              Thread.currentThread().interrupt();
            }
          } else {
            Optional.ofNullable(map.remove(ref)).ifPresent(r -> r.run());
          }
        }
      }
    }
  }
}

@@ -248,45 +248,228 @@
 ort 
-xdean.jex.util.reflect.ReflectUtil;%0D%0A
+io.reactivex.Scheduler;%0D%0Aimport io.reactivex.schedulers.Schedulers;%0D%0A%0D%0A/**%0D%0A * Provide a convenient way to do something on the moment when an object be collected by gc.%0D%0A *%0D%0A * @author Dean Xu (XDean@github.com)%0D%0A *%0D%0A */
 %0D%0Apu
@@ -517,16 +517,22 @@
  static 
+final 
 Map%3CRefe
@@ -551,19 +551,33 @@
 nnable%3E 
-map
+FINALIZE_TASK_MAP
  = new C
@@ -616,16 +616,22 @@
  static 
+final 
 Referenc
@@ -645,21 +645,21 @@
 Object%3E 
-queue
+QUEUE
  = new R
@@ -682,278 +682,20 @@
 );%0D%0A
-  private static Object lock;%0D%0A%0D%0A  static %7B%0D%0A    try %7B%0D%0A      lock = ReflectUtil.getFieldValue(ReferenceQueue.class, queue, %22lock%22);%0D%0A    %7D catch (NoSuchFieldException e) %7B%0D%0A      throw new Error(%22Can't find ReferenceQueue's lock, Check code and java version%22);%0D%0A    %7D%0D%0A
+%0D%0A  static %7B
 %0D%0A  
@@ -838,17 +838,8 @@
  %7B%0D%0A
-      ;%0D%0A
     
@@ -895,17 +895,16 @@
 Finalize
- 
 Support%22
@@ -950,16 +950,20 @@
 PRIORITY
+ - 2
 );%0D%0A    
@@ -1080,51 +1080,211 @@
     
-map.put(new PhantomReference%3C%3E(o, queue), r
+finalize(o, r, Schedulers.io());%0D%0A  %7D%0D%0A%0D%0A  public static void finalize(Object o, Runnable r, Scheduler s) %7B%0D%0A    FINALIZE_TASK_MAP.put(new PhantomReference%3C%3E(o, QUEUE), () -%3E s.createWorker().schedule(r)
 );%0D%0A
@@ -1483,39 +1483,8 @@
  %7B%0D%0A
-      synchronized (lock) %7B%0D%0A  
     
@@ -1521,23 +1521,38 @@
 ) %7B%0D%0A   
+     try %7B%0D%0A
        
+   
 Referenc
@@ -1581,18 +1581,20 @@
 f = 
-queue.poll
+QUEUE.remove
 ();%0D
@@ -1612,17 +1612,17 @@
 if (ref 
-=
+!
 = null) 
@@ -1640,47 +1640,98 @@
     
-try %7B%0D%0A              lock.wait();%0D%0A    
+Optional.ofNullable(FINALIZE_TASK_MAP.remove(ref)).ifPresent(r -%3E r.run());%0D%0A          %7D%0D%0A
     
@@ -1780,20 +1780,16 @@
         
-    
 Thread.c
@@ -1821,131 +1821,8 @@
 );%0D%0A
-            %7D%0D%0A          %7D else %7B%0D%0A            Optional.ofNullable(map.remove(ref)).ifPresent(r -%3E r.run());%0D%0A          %7D%0D%0A
     
@@ -1850,10 +1850,8 @@
 %0D%0A  %7D%0D%0A%7D
-%0D%0A

update FinalizeSupport, don't use reflect