user4512098
user4512098

Reputation:

How to protect private Thread without using SecurityManager

Like ThreadPoolExecutor class, I'm using private background thread in my class (MyClass).
However, once I start my thread, anyone can invoke my thread's method like this:

Thread[] threads = new Thread[10];
Thread.currentThread().getThreadGroup().enumerate(threads);
threads[**index of my thread**].run();

and this kind of invocation breaks structure of MyClass.

Of cource, I can use SecurityManager to avoid this,
but I can't force user of MyClass to run JVM with SecurityManager installed.
So, if I don't want to break structure of MyClass,
I have to write lengthy code like this:

@Override
public void run(){
    if(.....) throw new UnsupportedOperationException("do not invoke run() directly");
}

@Override
public void setUncaughtExceptionHandler(.....){
    throw new UnsupportedOperationException("cannot change handler");
}

........

Then, my question is "Who is the person responsible?"
Can I assume that no one invokes private thread's methods?
(imperfection caused by such invokation is negligible)
or
Do I have to prepare for illegal access?
(object have to be perfect in all cases)

and more generally,
Is there (official) programming standard about this kind of problem?

Thank you.

Upvotes: 0

Views: 108

Answers (3)

Solomon Slow
Solomon Slow

Reputation: 27115

Here's a follow-up thought: If you are writing a library that other programmers will use, then instead of trying to hide your threads from your client, you should be doing the opposite: When you want to create a new thread, you should allow your client to create it for you.

Use a ThreadFactory instance to create new threads.

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

ThreadFactory myThreadFactory = Executors.defaultThreadFactory();

public void setThreadFactory(ThreadFactory clientThreadFactory) {
    myThreadFactory = clientThreadFactory;
}

void someMethodThatMakesAThread(...) {

    Runnable r = new Runnable() {
        @Override
        public void run() {
            ...
        }
    };
    Thread t = myThreadFactory.newThread(r);
    t.start();
    ...
}

If the client chooses to call your setThreadFactory() method, then your code will use the client's ThreadFactory instance to make new threads. That gives the client a lot of power to debug the program, log thread creation events, control thread priorities, organize threads in ThreadGroups,... All of which makes your module more useful and more attractive to a programmer who wants to use it in a large program that has many other threads besides just yours.

On the other hand, if your client chooses not to call setThreadFactory() then the default ThreadFactory will basically just call new Thread(r) for you.

Upvotes: 1

jtahlborn
jtahlborn

Reputation: 53694

Expanding on @jameslarge's comment, when you build code for others to use, you don't need to worry about "malicious" usage. You should build your API to be easy to use correctly and hard to use incorrectly (through appropriate documentation and reasonable use of visibility levels like public/protected/private). It is not your job, however, to worry about whether or not someone will purposely call the wrong methods at the wrong times. If they do that, then they "void the warranty". I'm not sure if you are new to Java or not, but regardless of what "protections" you put in, there are all manner of ways to subvert code and mess with it (using reflection, decompiling/modifying/recompiling, etc).

As a side note, the SecurityManager is not there to protect the code from the user (e.g. DRM and its ilk), but is instead designed to protect the user from the code. Hence it is not a valid way to protect your code from being "misused" by another developer.

UPDATE

Deprecation is a more complicated question. Think about the situation where someone has been using your code for a while. Ideally, they should be able to upgrade to new versions and not modify their code (assuming the new version is reasonably compatible with the old version). In this case, if a deprecated method "still works" but is no longer the "right way", you wouldn't want to start throwing exceptions in previously working code. If, however, you've given your users lots of warning, and now this method no longer works at all, then yes, you want to throw an exception. That said, if you are creating an entirely new API and happen to be exposing a class with a deprecated method that you never want your users to use, then throwing an exception in that case is also reasonable.

Upvotes: 1

Germann Arlington
Germann Arlington

Reputation: 3353

If I were you I would consider the following:
1) the thread is not meant to be re-runnable, it should be started (and run) only once.
2) in order to get your thread from Thread.currentThread().getThreadGroup().enumerate(threads); you thread has to be running already.
3) Adding simple check if (isRunning()) { throw ... } at the start of your run() method should solve you problems

Upvotes: 0

Related Questions