ThreadDeath - How spooky is that!

R

Richard Maher

Hi,

I've got this: -

.. The best Applet infrastructure on the planet :)
.. Static arraylist of Sessions
.. Each Session has a TCP/IP Network Connection
.. Each connection has a Reader thread

Now, I can share memory beautifully between tabs/pages like there's no
tomorrow with the lovely single Reader thread covering all server-return
messages *until* there are no active pages for the applet. (I define
"active" as *any* page that has invoked the applet).

IOW, I provide a check-box which lets the user say "continue to live even
after the last page that referenced you has died" and it all looks sexy with
the connection et al hibernating till another page that references the
Applet is loaded. (You're getting excited I know; this really is that awe
inspiring!) Now I know the socket lives (many historical examples) and the
server receives my Applet's "send" but when the response is received in the
reader thread I get the dreaded "ThreadDeath" Error (not used to Errors
still strugling with Exceptions :)

So,
.. Does the thread have to die with the last Applet reference? (No problem, I
can code for that)
.. What is the Java Socket equivalent of a CANCEL() that will leave the
connection up but terminate the READ() so that the thread will be informed
to die?
.. I can re-create a Reader Thread next time Applet-RefCnt = 1
.. I can't kill the conneection; I need a SOFT stop-the-pending-read-and-die
thread method (but leave the socket up for Lazurus to use)

Cheers Richard Maher
 
A

Alessio Stalla

Hi,

I've got this: -

. The best Applet infrastructure on the planet :)
. Static arraylist of Sessions
. Each Session has a TCP/IP Network Connection
. Each connection has a Reader thread

Now, I can share memory beautifully between tabs/pages like there's no
tomorrow with the lovely single Reader thread covering all server-return
messages *until* there are no active pages for the applet. (I define
"active" as *any* page that has invoked the applet).

IOW, I provide a check-box which lets the user say "continue to live even
after the last page that referenced you has died" and it all looks sexy with
the connection et al hibernating till another page that references the
Applet is loaded. (You're getting excited I know; this really is that awe
inspiring!) Now I know the socket lives (many historical examples) and the
server receives my Applet's "send" but when the response is received in the
reader thread I get the dreaded "ThreadDeath" Error (not used to Errors
still strugling with Exceptions :)

So,
. Does the thread have to die with the last Applet reference? (No problem, I
can code for that)
. What is the Java Socket equivalent of a CANCEL() that will leave the
connection up but terminate the READ() so that the thread will be informed
to die?
. I can re-create a Reader Thread next time Applet-RefCnt = 1
. I can't kill the conneection; I need a SOFT stop-the-pending-read-and-die
thread method (but leave the socket up for Lazurus to use)

Cheers Richard Maher

You might want to read about NIO (asynchronous IO) that is in Java's
standard library since 1.4. I've never used it, but I believe it can
solve your problem (but requires a rewrite of the code that does i/o).

hth,
Alessio Stalla
 
R

Richard Maher

Hi Alessio,

Thanks for the response.

You might want to read about NIO (asynchronous IO) that is in Java's
standard library since 1.4. I've never used it, but I believe it can
solve your problem (but requires a rewrite of the code that does i/o).

I didn't like NIO (for reasons that evade me at the moment (one of which I
think was no connect timeout?)) but there are other options to explore
first.

Looking at the Stack Trace it appears AWT is the culprit. (My console Frame
disappears as well. Why I chose Frame over Dialog in this case I don't know.
I'll use the normal Parent Frame I've discovered for the other dialog boxes
and see if it can persist).

Thers's a AWT.AppContext.dispose(); ThreadGroup.stop() and ultimately a
Thread.Stop() (I had thought Thread.stop() was severely deprecated and
bug-inducing?)

Anyway first I'll see: -
.. If my thread can catch the Error and soldier on
.. If the change from Frame to Dialog does anything
.. Tear down the Frame/Dialog before the last Applet page leaves and
revuild-it again at 1
.. Put my thread in a different thread group (But it doesn't look like my
Reader is the Thread in question anyway)
.. Turn off isDaemon() but this might may the last applet page hang
.. And other shotgun fixes

Alternatively someone could give me the answer :)

Cheers Richard Maher

PS. Roedy you're also wrong about Applets not being able to locate a parent
Frame and use dialogs
 
R

Richard Maher

Hi,

Richard Maher said:
Anyway first I'll see: -
. If my thread can catch the Error and soldier on
. If the change from Frame to Dialog does anything
. Tear down the Frame/Dialog before the last Applet page leaves and
revuild-it again at 1
. Put my thread in a different thread group (But it doesn't look like my
Reader is the Thread in question anyway)
. Turn off isDaemon() but this might may the last applet page hang
. And other shotgun fixes

Alternatively someone could give me the answer :)

From the docs it looks like Applets "cannot manipulate Threads in other
ThreadGroups" so I take it creating a new ThreadGroup and trying to populate
it is a no-no, but can someone tell me if isAlive() and join() are
considered "manipulation"?

Also that the next virgin instantiation of the Applet inside a browser
instance with create a distict ThreadGroup to the last time it was
referenced in a page?
 
M

markspace

Richard said:
From the docs it looks like Applets "cannot manipulate Threads in other
ThreadGroups"

Do you have the link for that? I'm curious what you are reading.

so I take it creating a new ThreadGroup and trying to populate
it is a no-no,

Hmm, this doesn't sound right to me. Although I think ThreadGroups are
deprecated in general. Try an Executor instead.

but can someone tell me if isAlive() and join() are
considered "manipulation"?


Did you make the thread? If you did I think you are ok.

Did you look at these examples? They seem to make threads with no problems.

<http://java.sun.com/docs/books/tutorial/deployment/applet/threads.html>

<http://java.sun.com/docs/books/tutorial/deployment/applet/threadExample.html>

I'm guessing but I think we have another case of "bugs in the code you
are not showing us." Threads are fine, NIO is fine, you've just got a
bug to fix.
Also that the next virgin instantiation of the Applet inside a browser
instance with create a distict ThreadGroup to the last time it was
referenced in a page?

English much language first? Sorry, too many grammar and spelling
mistakes for me to take a stab at what this means.
 
R

Richard Maher

Hi Mark,

markspace said:
Do you have the link for that? I'm curious what you are reading.

Can't recall the exact link but they're not hard to find eg: -
http://www.docjar.com/docs/api/sun/applet/AppletSecurity.html
www.docjar.org/src/api/sun/applet/AppletSecurity.java
Hmm, this doesn't sound right to me.

Can you please show me one of your examples of an Applet creating a
top-level ThreadGroup (that is not parented by the Applet ThreadGroup) and
then create and start a Thread in it?
Although I think ThreadGroups are
deprecated in general. Try an Executor instead.

Will an Executor allow me to create a Thread in an Applet that the JVM won't
ThreadDeath when the Applet goes away?
Did you make the thread?

I did.
If you did I think you are ok.

Me too. (When it comes to those two methods anyway).
Did you look at these examples? They seem to make threads with no problems.
<http://java.sun.com/docs/books/tutorial/deployment/applet/threadExample.htm
l>

It's just a little bit more complicated than that.
I'm guessing but I think we have another case of "bugs in the code you
are not showing us." Threads are fine, NIO is fine, you've just got a
bug to fix.

Does anyone have a NIO example of an effective "cancel" on a Socket read
that will leave it in a predictable and consistent state? One that loops
around until it is sure the TCP/IP stream has delivered the requisite header
bytes, and that will make sure that the Socket has been drained of any
residual bytes up to the msgLen that was contained in the header would be
nice :) Also, don't forget that the cancel can occur anywhere. (I'm not
implying that it can't be done; I've never used NIO. I just can't see it
buying me anything here. Sure - cancel the (possible) Read, tidy-up, and end
the Thread - but the issues/details look the same to me at the moment)
English much language first? Sorry, too many grammar and spelling
mistakes for me to take a stab at what this means.

Look, here's the scenario I'm looking at: -

1) My readerThread is happily reading on a Socket when the user changes
pages from the last wep-page/tab that referenced the Applet. SUN in it's
wisdom then says Thread.stop() is the best thing to do. (Part of the default
Applet ThreadGroup to be zapped)
2) If my Applet is currently waiting on a Socket read then nothing happens
and the thread just sits there saying "Stuff-you!".
3) The user returns to a page that contains the Applet
4) The readerThread needs recycling (One could just trap ThreadDeath and
soldier-on but but with all monitor locks also zapped it's probably not
recommended :)
5) Until the new Applet sends a message request, to which the server will
respond, the original readerThread won't know to tidy-up and die.
6) I'm checking out the feasibility of having the new readerThread join()
the original readerThread and wait for it to leave the socket at a
"message-boundry".
7) My impression was that these two seperate instances of the Applet would
have distinct ThreadGroups, hence my concern over the security implications
of join() and isAlive() on a such a thread but I'm optimistic here.
8) If I could create my reader in ThreadGroup that didn't have the Applet
ThreadGroup as its parent then it wouldn't be ThreadDeathed and all would be
peachy. (Except I suppose for the user with unwanted threads all over the
place)
9) Yes, I could just close the Socket when the last Applet instance/page/tab
leaves but I'll persevere a little longer for something I see as worthwhile.

Regards Richard Maher

PS. If someone knows how to keep an AWT Frame (that was created in an
applet) up when there are no remaining applets referencing it (but the
browser lives), then I'd like to know that too.
 
M

markspace

Richard said:

Ah ok, the checkAccess() method. Here's a Google books link with some
more info on exactly what methods in Thread and ThreadGroup call
checkAccess().

<http://books.google.com/books?id=mB..._1_vQdNjb&dq=java thread checkAccess&pg=PA247>


As for the rest, I'm a little confused why you think that the applet
needs to continue running even after a page has been switched out.
That's like a virus or something. When I leave a page, I want that
applet to die, right away. Anything else will likely annoy your users
such that they no longer visit your page at all. Could you tell us what
it is you are trying to do that's so important that you must continue
running even when the page is hidden?

If you really have to have an applet persist outside of a web page, then
I think you should be using JWS, not applets.
 
R

Richard Maher

Hi Mark,

markspace said:
As for the rest, I'm a little confused why you think that the applet
needs to continue running even after a page has been switched out.

I neither want nor need the Applet to continue running, and I never have.
The Applets have gone, destroy()ed, dead as a Do Do. (I believe the JVM will
ThreadDeath them too if destroy() doesn't behave.) I just expect the static
class variables, that the Applet was using, to survive - and they do. (Happy
to see that new Java 6 Applet Param to preserve the old behaviour too!)

My Session Status info and Network connection are all tickety boo. Beautiful
cross-tab, multi-applet support, as tab after tab, page after page, comes
and goes! Each page pounding the single connection(1) with SEND requests and
the one lovely readerThread distributing the results to the appropriate
page. Now you don't sound like the type of bloke to be too impressed with
that functionality but I assure you that there are one or two jaws dropping
in awe at the possibilities.

Now, I had hoped that the Thread in question was just another class-variable
but I can understand the concerns and the restriction. Which is why I came
looking for anyone who'd know why my work-around number two would not work
before I invested a fair bit of time in it. (A callback(PLEASEDIE) would've
been better than Thread.stop() but hey.)
That's like a virus or something.

Again one or two people around the world at the moment are quite excited
about Single Sign-On possibilities and are paying a lot of money for
bollocks solutions. I guess you have cookies and JavaScript turned off then?
Leave applets turned off as well and you can sleep safely. Me, I don't write
anything to disk, or outside the sand-box rules for an *unsigned* applet. I
just use up some memory.
When I leave a page, I want that
applet to die, right away.

What constitues an "Applet" to you? All the class variables as well? If so
you should write a letter to SUN/Oracle and complain.
Anything else will likely annoy your users
such that they no longer visit your page at all.

In this current version the "Logoff when leaving last page" behaviour is
optional. I give the web-page developers the ability to specify it in the
Tier3Client JavaScript object, and on the Tier3Console Frame there is a
Tick-Box where the user can override the setting. (There is also a LOGOFF
button on the console that will run around all participating tabs replacing
them with a logoff page of your choice. A Messages/Bytes Sent/Received. A
TextArea that could possibly be used as a UDP message grabber. All shit-hot
stuff but maybe it's just me?)
Could you tell us what
it is you are trying to do

I honestly don't think my English is up to explaining it to you further. But
I'm sure there are plenty of others you can "help".
that's so important

It's honestly not important. If I had to tell people "If you don't want to
have to log-on again then keep at least one participating page up" then that
would not be the end of the world. I still might go that way for V1.0 it it
all gets too hard.

Shouldn't be many more weeks away now (time-permitting)
that you must continue
running even when the page is hidden?

The page isn't hidden the page is gone. You're not getting this are you?
If you really have to have an applet persist outside of a web page, then
I think you should be using JWS, not applets.

Nah, I'm good with the whole browser-based, signle sign-on, single
persistent connection, feeding the Adobe FABridge or Silverlight HTML bridge
deal, but hey it's not for everyone. Having said that, it's not all finished
and still could all go tits-up with a show-stopper; who knows?

Anyway, good-luck with that web-start stuff.

Regaqrds Richard Maher

(1) There can be multiple connections if multiple Applets are present. (Also
instances of the same Applet will result in different connections if
different parameters were used (host, port, etc) or the topDocHost varies.

PS. Who is the "us" you keep refering to? Is there some group you represent
or are spokesman for?

PPS. Stopped of in Mauritius for two weeks on the way back from London 4
years ago and was surprised to find that's where Do Dos came from.
 
O

Oxide Scrubber

Richard said:
Now, I had hoped that the Thread in question was just another class-variable
but I can understand the concerns and the restriction.

What about accessing that Thread indirectly, via a static method like

public static Thread getTheThread () {
if (!theThread.isAlive())
theThread = new Thread(theRunnable);
return theThread;
}

That will return the existing thread, if it is still alive, and if it
has been killed it will replace it. So if the user closes that last tab,
and then later reopens one, a new thread will be created.

Any important state that was in the Thread object and should be
preserved will have to be moved to the (hypothetical) theRunnable or
some other object. But that's about it.
 
R

Richard Maher

Hi Oxide,

Oxide Scrubber said:
What about accessing that Thread indirectly, via a static method like

public static Thread getTheThread () {
if (!theThread.isAlive())
theThread = new Thread(theRunnable);
return theThread;
}

That will return the existing thread, if it is still alive, and if it
has been killed it will replace it.

It's a bit more complicated in that the first thread is more than likely
stuck reading the socket. I don't want to close the socket, and the server
won't send anything until it's asked to. So the new Applet reader must
wait/join the old/reader in anticipation of the web-page/JS calling send()
which will generate a response which will finally let ThreadDeath in with
his scythe and tell the thread to die (or work out how many bytes you've got
left to read, put it where the other thread can find it, and then die)

The big issue is SUN's decree that the original Thread is irrecoverably
damaged and must die. (If that's more like "guidelines" and the Pirate Code
then let me know :)
So if the user closes that last tab,
and then later reopens one, a new thread will be created.

That's the plan. It's just the old thread's socket-inspired, monty
python-eaque, unwillingness to die that is the fly in the ointment: -
1) Must leave the Socket empty or at a message boundry
2) Must not read messages destined for the new readerThread
3) Doesn't matter if the new reader get's old/out-of-date messages for which
there is no matching target window/tab
4) The good news is that we'll only get one ThreadDeath even though it can
occur anywhere
Any important state that was in the Thread object and should be
preserved will have to be moved to the (hypothetical) theRunnable or
some other object. But that's about it.

The problem is the "undefined" state of the readerThread after a ThreadStop.
To be honest, in initial testing, just trapping ThreadDeath and soldiering
on *appeared* to work like a charm but when the doc says that any monitor
locks are zapped and all sorts of other advice/frighteners then it's best to
replace it. (Yes with NIO I imagine that in the destroy() method of the last
Applet instance I could cancel any pending read and then gracefully end the
thread before the JVM but I'm still without a useful cancel_socket_read()
example and even then I think the thread/message-boundry clean-up will be as
cumbersome?)

Regards Richard Maher
 
O

Oxide Scrubber

Richard said:
The problem is the "undefined" state of the readerThread after a ThreadStop.
To be honest, in initial testing, just trapping ThreadDeath and soldiering
on *appeared* to work like a charm but when the doc says that any monitor
locks are zapped and all sorts of other advice/frighteners then it's best to
replace it. (Yes with NIO I imagine that in the destroy() method of the last
Applet instance I could cancel any pending read and then gracefully end the
thread before the JVM but I'm still without a useful cancel_socket_read()
example and even then I think the thread/message-boundry clean-up will be as
cumbersome?)

So the thread doesn't die early enough because it's blocking on I/O?
Maybe you need to use NIO then.
 
M

markspace

Richard said:
What constitues an "Applet" to you? All the class variables as well? If so
you should write a letter to SUN/Oracle and complain.


Actually, yes. All class variables and the class itself should be
purged when no longer used.

Does anyone know how to detect when a class is removed from memory? I
was able to reproduce Richard's (the OP) thread death error with a
little thought and effort, but nothing occurs to me off hand about how
to verify that a class has been removed from memory.

Anyway, yes it sounds like you are relying on a bug of some sort to do
your "single sign-on." This doesn't seem to me like a great plan.
 
M

markspace

markspace said:
Does anyone know how to detect when a class is removed from memory? I
was able to reproduce Richard's (the OP) thread death error with a
little thought and effort, but nothing occurs to me off hand about how
to verify that a class has been removed from memory.


I just did a quick ad-hoc test. On my system, classes are retained for
about 30 seconds, then dumped, along with all their class variables. No
need for a bug report, all seems working normally.
 
R

Richard Maher

Hi Mark,

markspace said:
I just did a quick ad-hoc test. On my system, classes are retained for
about 30 seconds, then dumped, along with all their class variables. No
need for a bug report, all seems working normally.

Really? That could save me a lot of work this week-end.

What version of Browser, OS, and JVM were you using?

If it's Java 6, did you have the "classloader_cache" applet parameter set to
true?

Can you please post your Applet code so that I can try here?

This thread made me remember: -
http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/91a548f39b86c382?fwc=2

Which itself referenced:-
http://forums-beta.sun.com/thread.jspa?messageID=513241

Where, in response to the claim "The static variables last for the life of
the program", jschell said
[[[[[[[[[[[[[[
Not exactly.

Static variables last until the class loader is unloaded. If there is no
user defined class loader then the system class loader is used. And the
system class loader is never unloaded. So for classes loaded via the system
class loader that explaination is correct.
]]]]]]]]]]]]]]]

Now I don't know who JSCHELL is (Looks like I wrongly recalled him working
for SUN) and I don't know if "platinum Duke Stars" mean anything, but if
he's right then you've managed to unload the JVM system class loader while
the browser is still running. How did you do that? Or are you not using the
System Class Loader?

You are running an Applet in a Browser aren't you?

Regards Richard Maher
 
R

Richard Maher

Hi Mark,

markspace said:
Firefox 3, Vista, Java 1.6 something (the latest).




Yes. Which is to say I left it at its default value.




It's pretty simple. This code will print "test = 0" when it is loaded
fresh and "test = 1" when it is used from the applet cache:

<CODE>
package testapplet;
import javax.swing.JApplet;

public class TestApplet extends JApplet {

static int test;

@Override
public void init() {
System.out.println( "Init" );
System.out.println( "static int test = " + test );
test = 1;
}

@Override
public void start() {
System.out.println( "Start" );
new Thread() {
@Override
public void run() {
System.out.println( this );
try {
for(;;);
} catch (Error er ) {
System.err.println( er );
}
}
}.start();
}

@Override
public void stop() {
System.out.println( "Stop" );
}

@Override
public void destroy() {
System.out.println( "Destroy" );
}

}
</CODE>

Here's the applet tag I used in the web page:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Hello World!</h1>
<applet code="testapplet.TestApplet"
archive="AppletOne.jar"/>
</body>
</html>

Thanks very much for the example!
Nope, I just waited for the JVM itself to stop. The plug-in does that
once it is no longer used.

Mine doesn't seem to. This is perplexing (for me anyway) Looks like you're
writing to the Java console; does the console window too just disappear
after 30 secs? Was was the console output before it disappeared?
Just had something go live so I'm knackered and will jump into bed but
didn't want you to think I was dodging the post or ungrateful.

Thanks again. I'll look more on tomorrow or w/e.

Regards Richard Maher

PS. File URL/codebase have anything to do with it? Some other settings I've
got that you ain't? I'm seeing things again :)
 
M

markspace

Richard said:
Mine doesn't seem to. This is perplexing (for me anyway) Looks like you're
writing to the Java console; does the console window too just disappear
after 30 secs? Was was the console output before it disappeared?


Yes, after the console window disappears, the JVM has been unloaded (I
believe, anyway). When that happens you should see the applet print
"test = 0" again. Until the console window disappears, when you browse
back to the page with the applet, you'll see the static value "test = 1"
printed.

I just checked it again and this time it took about 60 seconds for the
console window to disappear, so be prepared for some variability.
 
R

Richard Maher

Hi Mark,

markspace said:
Yes, after the console window disappears, the JVM has been unloaded (I
believe, anyway). When that happens you should see the applet print
"test = 0" again. Until the console window disappears, when you browse
back to the page with the applet, you'll see the static value "test = 1"
printed.

I just checked it again and this time it took about 60 seconds for the
console window to disappear, so be prepared for some variability.

Well I suppose that's what I get for developing on ancient base versions,
and taking a punt on upward compatibility :-(

I think my feelings about SUN not proffering as much as a release note (let
alone an option to preserve existing behaviour) can best be summed up by
demonduck in: -
http://forums.java.net/jive/thread.jspa?threadID=62446&tstart=0

Anyway the good news is, I don't have to spend any more time chasing down a
ThreadDeath. When the last Applet is departing I'll close the Socket and
join() the readerThread as per usual. Thanks for saving my weekend.

If anyone wants to preserve the pre-existing and very useful functionality
of the applet's JVM surviving page exit then I suggest you untick the
"Enable Next Generation Plug-in" option on your Java control panel. This
seems to work for IE and FF but Chrome seems to kill the JVM immediately on
exit regardless of any options. Safari on the other hand appears to leave
the JVM up as per the traditional M.O.

An Applet parameter for "keepalive" or "timeout" would've been nice but as I
said before it's not that important (in this case) so I'm not gonna lose
sleep over it.

Thanks again.

Regards Richard Maher
 
R

Richard Maher

Hi Mark,

markspace said:
There's compatibility and then there's unintended side effects.

I say tomaRto.
The
static variable thing was always a weird side effect of how applets were
implemented. Now the new scheme is much more robust and I'm happy with
it, myself.

Me thinks you'd much prefer it if the classloader_cache default was "false",
or not available at all. That way presumptuous bastards like me and DD would
get what's coming to us? God bless Pogo games et al or they may have done
away with us for good :-(
It's never a good idea to rely on platform dependent side effects in
your code. It's guaranteed to break later.

Had another look around and although I'm still happy to give up on a "nice
to have" others may want to experiment with the applet parameter
LEGACY_LIFECYCLE. I couldn't find exact documentation but the Java 6 release
notes reaffirms support and there are several bugs open(ish) about verying
behaviour dependent on "Use New Generation Plug-in" settings.

Be warned that I think this changes the lifecycle to such an extent that
applet.destroy() does not get called at all when you leave the page and the
applet keeps running but hey, if you're desperate?

I believe it came out in 1.4.? and was intended primarily for Oracle Forms
who needed it. (Now Oracle owns Java maybe SUN employees will be a little
less Bolshie?)

Once again, Google Chrome says "No!", but someone has a non-confirmed bug
open against it.
That guy is a dick-head. Period. He ignores perfectly good advice and
is snide with people who are trying to explain what is going on.




Thanks for reporting back your findings. I hadn't realized that the
applet behavior was so variable. It's good to have a broader picture.



As mentioned in demonduck's thread there AppletContext.setStream() for
this.

If you could show me an example of using those methods to keep a socket
connection open between JVMs then that'd be a neat trick! (If not a source
of much security anxiety)

Regards Richard Maher
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top