@@ -45,35 +45,11 @@ public static Cleaner getCleaner() {
45
45
}
46
46
47
47
private final ReferenceQueue <Object > referenceQueue ;
48
- private final Thread cleanerThread ;
48
+ private Thread cleanerThread ;
49
49
private CleanerRef firstCleanable ;
50
50
51
51
private Cleaner () {
52
52
referenceQueue = new ReferenceQueue <Object >();
53
- cleanerThread = new Thread () {
54
- @ Override
55
- public void run () {
56
- while (true ) {
57
- try {
58
- Reference <? extends Object > ref = referenceQueue .remove ();
59
- if (ref instanceof CleanerRef ) {
60
- ((CleanerRef ) ref ).clean ();
61
- }
62
- } catch (InterruptedException ex ) {
63
- // Can be raised on shutdown. If anyone else messes with
64
- // our reference queue, well, there is no way to separate
65
- // the two cases.
66
- // https://groups.google.com/g/jna-users/c/j0fw96PlOpM/m/vbwNIb2pBQAJ
67
- break ;
68
- } catch (Exception ex ) {
69
- Logger .getLogger (Cleaner .class .getName ()).log (Level .SEVERE , null , ex );
70
- }
71
- }
72
- }
73
- };
74
- cleanerThread .setName ("JNA Cleaner" );
75
- cleanerThread .setDaemon (true );
76
- cleanerThread .start ();
77
53
}
78
54
79
55
public synchronized Cleanable register (Object obj , Runnable cleanupTask ) {
@@ -83,34 +59,43 @@ public synchronized Cleanable register(Object obj, Runnable cleanupTask) {
83
59
}
84
60
85
61
private synchronized CleanerRef add (CleanerRef ref ) {
86
- if (firstCleanable == null ) {
87
- firstCleanable = ref ;
88
- } else {
89
- ref .setNext (firstCleanable );
90
- firstCleanable .setPrevious (ref );
91
- firstCleanable = ref ;
62
+ synchronized (referenceQueue ) {
63
+ if (firstCleanable == null ) {
64
+ firstCleanable = ref ;
65
+ } else {
66
+ ref .setNext (firstCleanable );
67
+ firstCleanable .setPrevious (ref );
68
+ firstCleanable = ref ;
69
+ }
70
+ if (cleanerThread == null ) {
71
+ Logger .getLogger (Cleaner .class .getName ()).log (Level .FINE , "Starting CleanerThread" );
72
+ cleanerThread = new CleanerThread ();
73
+ cleanerThread .start ();
74
+ }
75
+ return ref ;
92
76
}
93
- return ref ;
94
77
}
95
78
96
79
private synchronized boolean remove (CleanerRef ref ) {
97
- boolean inChain = false ;
98
- if (ref == firstCleanable ) {
99
- firstCleanable = ref .getNext ();
100
- inChain = true ;
101
- }
102
- if (ref .getPrevious () != null ) {
103
- ref .getPrevious ().setNext (ref .getNext ());
104
- }
105
- if (ref .getNext () != null ) {
106
- ref .getNext ().setPrevious (ref .getPrevious ());
107
- }
108
- if (ref .getPrevious () != null || ref .getNext () != null ) {
109
- inChain = true ;
80
+ synchronized (referenceQueue ) {
81
+ boolean inChain = false ;
82
+ if (ref == firstCleanable ) {
83
+ firstCleanable = ref .getNext ();
84
+ inChain = true ;
85
+ }
86
+ if (ref .getPrevious () != null ) {
87
+ ref .getPrevious ().setNext (ref .getNext ());
88
+ }
89
+ if (ref .getNext () != null ) {
90
+ ref .getNext ().setPrevious (ref .getPrevious ());
91
+ }
92
+ if (ref .getPrevious () != null || ref .getNext () != null ) {
93
+ inChain = true ;
94
+ }
95
+ ref .setNext (null );
96
+ ref .setPrevious (null );
97
+ return inChain ;
110
98
}
111
- ref .setNext (null );
112
- ref .setPrevious (null );
113
- return inChain ;
114
99
}
115
100
116
101
private static class CleanerRef extends PhantomReference <Object > implements Cleanable {
@@ -125,6 +110,7 @@ public CleanerRef(Cleaner cleaner, Object referent, ReferenceQueue<? super Objec
125
110
this .cleanupTask = cleanupTask ;
126
111
}
127
112
113
+ @ Override
128
114
public void clean () {
129
115
if (cleaner .remove (this )) {
130
116
cleanupTask .run ();
@@ -151,4 +137,42 @@ void setNext(CleanerRef next) {
151
137
public static interface Cleanable {
152
138
public void clean ();
153
139
}
140
+
141
+ private class CleanerThread extends Thread {
142
+
143
+ private static final long CLEANER_LINGER_TIME = 30000 ;
144
+
145
+ public CleanerThread () {
146
+ super ("JNA Cleaner" );
147
+ setDaemon (true );
148
+ }
149
+
150
+ @ Override
151
+ public void run () {
152
+ while (true ) {
153
+ try {
154
+ Reference <? extends Object > ref = referenceQueue .remove (CLEANER_LINGER_TIME );
155
+ if (ref instanceof CleanerRef ) {
156
+ ((CleanerRef ) ref ).clean ();
157
+ } else if (ref == null ) {
158
+ synchronized (referenceQueue ) {
159
+ if (firstCleanable == null ) {
160
+ cleanerThread = null ;
161
+ Logger .getLogger (Cleaner .class .getName ()).log (Level .FINE , "Shutting down CleanerThread" );
162
+ break ;
163
+ }
164
+ }
165
+ }
166
+ } catch (InterruptedException ex ) {
167
+ // Can be raised on shutdown. If anyone else messes with
168
+ // our reference queue, well, there is no way to separate
169
+ // the two cases.
170
+ // https://groups.google.com/g/jna-users/c/j0fw96PlOpM/m/vbwNIb2pBQAJ
171
+ break ;
172
+ } catch (Exception ex ) {
173
+ Logger .getLogger (Cleaner .class .getName ()).log (Level .SEVERE , null , ex );
174
+ }
175
+ }
176
+ }
177
+ }
154
178
}
0 commit comments