I understand the source code jdbc driver mysql. I came across the fact that in the class com.mysql.jdbc.NonRegisteringDriver when creating a connection, a phantom reference is created. These links are then processed in the background thread. Please explain why using such complex logic if you can simply override the finalize() method in the com.mysql.jdbc.ConnectionImpl class
1 answer
I will answer myself, as a result of a small investigation, found out the following:
Previously, the jdbc mysql driver used the finalize() method to close connections. But it was abandoned because of the "terrible" inefficiency. For more on this, see the release notes . Particularly curious can see the commit .
The question remains why finalize() not effective. As I understand it, it is executed in the gc thread, which calls objects on objects finalize() . PhantomReference however, handles links in a separate thread, due to which some winnings occur, since the overall assembly process does not slow down and the "more attention" objects are processed earlier, and do not stand together with other objects in the queue.
You can check this by the following test:
public class Solution { private static final LongAdder increment = new LongAdder(); public static void main(String[] args) throws Exception { int count = 1_000_000; //Π½Π°ΠΊΠΈΠ΄ΡΠ²Π°Π΅ΠΌ ΡΠ°Π±ΠΎΡΡ Π΄Π»Ρ gc Collection trash = getSimpleObjects(count); trash.clear(); //ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡΡ Ρ ΡΠ°Π½ΡΠΎΠΌΠ½ΡΠΌΠΈ ΡΡΡΠ»ΠΊΠ°ΠΌΠΈ Collection<Object> objects = getObjectsPhantomReferences(count); long time = System.currentTimeMillis(); objects.clear(); System.gc(); while (increment.longValue() != count) ; System.out.println(System.currentTimeMillis() - time); increment.reset(); //Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΆΠ΄Π΅ΠΌ TimeUnit.SECONDS.sleep(20); //Π½Π°ΠΊΠΈΠ΄ΡΠ²Π°Π΅ΠΌ ΡΠ°Π±ΠΎΡΡ Π΄Π»Ρ gc trash = getSimpleObjects(count); trash.clear(); //ΡΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡΡ Ρ ΠΏΠ΅ΡΠ΅ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΠΌΠΈ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠΌ finalize() objects = getObjectsWithFinalize(count); time = System.currentTimeMillis(); objects.clear(); System.gc(); while (increment.longValue() != count); System.out.println(System.currentTimeMillis() - time); } private static Collection<Object> getSimpleObjects(int count) { Collection<Object> objects = new ArrayList<>(count); for (int i = 0; i < count; i++) objects.add(new Object()); return objects; } private static Collection<Object> getObjectsWithFinalize(int count) { Collection<Object> objects = new ArrayList<>(count); for (int i = 0; i < count; i++) objects.add(new Object() { @Override public void finalize() throws Throwable { super.finalize(); Solution.finalize(this); } }); return objects; } private static Collection<Object> getObjectsPhantomReferences(int count) { Collection<Object> objects = new ArrayList<>(count); for (int i = 0; i < count; i++) { Object obj = new Object(); objects.add(obj); Cleaner.create(obj, () -> finalize(null)); } return objects; } private static void finalize(Object o) { increment.increment(); } } Obviously, the test is inaccurate, because System.gc() can cause garbage collection with some delay, if at all.