Thanks for guidance, I will try it later. Reverted in revision: 728536
Jacques

From: "Adam Heath" <[email protected]>
Jacques Le Roux wrote:
Hi Adam,

I don't mind to revert this patch, but I think it's nice to have this
feature.
I suppose that what you call "multiple calls in series" are expressions
like (and yes it's not synchronized, my bad !)

+            for (Appender appender : appenders) {
+                if (appender != null &&
appender.getName().equals(appenderName)) {
+                    return appender;
+                }

No, that's not what I mean.

Could we not replace Vector (bad I agree) by synchronizedMap and use
synchronization on the synchronized Map, like in
http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html#synchronizedList(java.util.List)

Foo hasFoo() {
 synchronized (fooContainer) {
 }
}

void setFoo() {
 synchronized (fooContainer) {
 }
}

Foo getFoo() {
 if (!hasFoo()) setFoo();
 return getFoo();
}

This is the pattern that is in this patch, and it's a race condition.

In addition, synchronizing on the internal Collection(the value in the
map) isn't always worth it, if you are already inside a synchronized
block on some other variable.



For the memorty leaks, I think removeAppenderFromThreadGroupMap would be
OK, isn'it ?

Integer.toString(), not "" + int.
is bad I agree

Also here result is not genericized as it was "before" (but I guess the
patch was anterior too the genericization, and I did not spot that also,
maybe there are more I will be carefull on this aspect too)

-            Map<String, Object> result =
dispatcher.runSync(getServiceName(), getContext());
+
+            if (this.logLocation != null) {
+                Debug
+                .registerCurrentThreadGroupLogger(this.logLocation,
+                        appenderName);
+            }
+            Map result = dispatcher.runSync(getServiceName(),
getContext());

So, by usint also FlexibleLocation instead of File, don't you think we
could amend this "patch" instead of simply reverting it ?

No, because there are issues with memory loss too, due to the
reimplementation of what ThreadLocal actually accomplishes.

What would be better, is to implement a singleton per-thread
initialization and cleanup system.

==
void ThreadWorker.run() {
 try {
   doWork();
 } finally {
   ThreadInit.runCleanup();
 }
}

static <T> T ThreadInit.getInitObject(ThreadInit<T> init) {
 Map<Class<? extends ThreadInit>, InitData> initMap = tl.get();
 if (initMap == null) {
   initMap = FastMap.newInstance();
   tl.set(initMap);
 }
 InitData<T> initData = initMap.get(init.getClass());
 if (initData != null) return initData.getValue();
 T initValue = init.start();
 initMap.put(init.getClass(), new InitData<T>(init, initValue));
 return initValue;
}

static void ThreadInit.runCleanup() {
 Map<Class<? extends ThreadInit>, InitData<?>> initMap = tl.get();
 if (initMap == null) return;
 for (InitData<?> initData: initMap.values()) {
   runCleanup(initData);
 }
}

static <T> void ThreadInit.runCleanup(InitData<T> initData) {
 initData.getInit().runCleanup(initData.getValue());
}
==

This allows any random code anywhere to have init code that runs *once*
per thread invocation; it just requires that very early in the
invocation chain, is a try/finally block, that runs the cleanup code.

It's also possible to extend this slightly, so there is a concept of
push/pop ThreadLocal state.

You'll note there is *no* synchronization here.  This is because the
top-level variable that holds the object graph, is a ThreadLocal.
Synchronization is only used for cross-thread control.  ThreadLocal is
local, and can't corrupt across threads.

Reply via email to