> ## `java.security.AccessControlException` thrown in `stop`, `suspend`, or `resume` method of `java.lang.Thread`

> ###
> Symptoms

> > When running an applet in a browser using the Sun JRE, an `AccessControlException` is thrown in the `stop`, `suspend`, or `resume` method of `java.lang.Thread`.
> > `java.security.AccessControlException: access denied (java.lang.RuntimePermission modifyThread)
> > at java.security.AccessControlContext.checkPermission(Unknown Source)
> > at java.security.AccessController.checkPermission(Unknown Source)
> > at java.lang.SecurityManager.checkPermission(Unknown Source)
> > at sun.applet.AppletSecurity.checkAccess(Unknown Source)
> > at java.lang.Thread.checkAccess(Unknown Source)
> > at java.lang.Thread.stop(Unknown Source)
> > at ....`
> > The same applet runs under the Microsoft VM.

> ### Cause

> > This exception is caused by calling these methods on a dead `Thread` object in the Sun JRE.
> > The Java class libraries in the Sun JRE have changed over time. Some APIs have been clarified, some have been deprecated, and some have had their implementation altered.

> > The result of calling `stop`, `suspend`, and `resume` on a dead `Thread` object was not well defined. In the Microsoft VM, they result in a no-op. However, in the Sun JRE, calling these methods on a dead `Thread` object invalidates the underlying invariant of the implementation, thus resulting in an `AccessControlException`.

> ### Resolution

> The `Thread` `stop`, `suspend`, and `resume` methods are inherently unsafe and have been deprecated in the Java 2 platform.

> To work around this problem, replace calls to `stop`, `suspend`, and `resume` with code that simply modifies some variable to indicate that the target thread should stop/suspend/resume.
> For example, suppose your applet contains the following methods:

>         private Thread blinker;

>         public void start() {
>             blinker = new Thread(this);
>             blinker.start();
>         }

>         public void stop() {
>             blinker.stop();  // UNSAFE!
>         }

>         public void destroy() {
>             blinker.stop();  // UNSAFE and WILL throw AccessControlException in the Sun JRE!
>         }

>         public void run() {
>             Thread thisThread = Thread.currentThread();
>             while (true) {
>                 try {
>                     thisThread.sleep(interval);
>                 } catch (InterruptedException e){
>                 }
>                 repaint();
>             }
>         }

> You can avoid the use of `Thread.stop` by replacing the applet's `stop`, `destroy,` and `run` methods with:

>         private volatile Thread blinker;

>         public void stop() {
>             blinker = null;
>         }

>         public void destroy() {
>             blinker = null;
>         }

>         public void run() {
>             Thread thisThread = Thread.currentThread();
>             while (blinker == thisThread) {
>                 try {
>                     thisThread.sleep(interval);
>                 } catch (InterruptedException e){
>                 }
>                 repaint();
>             }
>         }

> Another example: Suppose your applet contains the following `mousePressed` event handler, which toggles the state of a thread called `blinker`:

>         private boolean threadSuspended;

>         public void mousePressed(MouseEvent e) {
>             e.consume();

>             if (threadSuspended)
>                 blinker.resume();
>             else
>                 blinker.suspend();  // DEADLOCK-PRONE!

>             threadSuspended = !threadSuspended;
>         }

>         public void run()
>         {
>     	 while (true) {
>             try {
>                 Thread.currentThread().sleep(interval);
>             } catch (InterruptedException e){
>             }
>             repaint();
>         }

> You can avoid the use of `Thread.suspend` and `Thread.resume` by replacing the event handler above with the following:

>         private boolean volatile threadSuspended;

>         public synchronized void mousePressed(MouseEvent e) {
>             e.consume();

>             threadSuspended = !threadSuspended;

>             if (!threadSuspended)
>                 notify();
>         }

>         public void run() {
>             while (true) {
>                 try {
>                     Thread.currentThread().sleep(interval);

>                     if (threadSuspended) {
>                         synchronized(this) {
>                             while (threadSuspended)
>                                 wait();
>                         }
>                     }
>                 } catch (InterruptedException e){
>                 }
>                 repaint();
>             }
>         }

> ### Related Information

> > Why Are `Thread.stop`, `Thread.suspend`, `Thread.resume`, and `Runtime.runFinalizersOnExit` Deprecated?