如何在不使用 SecurityManager 的情况下保护私有线程

How to protect private Thread without using SecurityManager

ThreadPoolExecutor class 一样,我在 class (MyClass).
中使用 private 后台线程 但是,一旦我 start 我的线程,任何人都可以像这样调用我线程的方法:

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

并且这种调用破坏了 MyClass.

的结构

当然,我可以使用SecurityManager来避免这种情况,
但我不能强制 MyClass 的用户使用 运行 安装了 SecurityManager 的 JVM。
所以,如果我不想破坏 MyClass
的结构 我必须像这样编写冗长的代码:

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

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

........

那么,我的问题是"Who is the person responsible?"
我可以假设没有人调用私有线程的方法吗?
(这种调用造成的缺陷可以忽略不计)
或者
我需要为非法访问做准备吗?
(对象在所有情况下都必须是完美的)

更一般地说,
是否有关于此类问题的(官方)编程标准?

谢谢。

如果我是你,我会考虑以下几点:
1) 线程并不是要重新运行启用,它应该只启动一次(和运行)。
2) 为了从 Thread.currentThread().getThreadGroup().enumerate(threads); 获得您的线程,您的线程必须已经 运行ning。
3) 在你的 run() 方法的开头添加简单的检查 if (isRunning()) { throw ... } 应该可以解决你的问题

扩展@jameslarge 的评论,当您构建代码供他人使用时,您无需担心 "malicious" 使用问题。您应该将 API 构建为易于正确使用且难以错误使用(通过适当的文档和合理使用像 public/protected/private 这样的可见性级别)。然而,不是您的工作,担心是否有人会故意在错误的时间调用错误的方法。如果他们这样做,那么他们 "void the warranty"。我不确定你是否是 Java 的新手,但无论你输入什么 "protections",都有各种方法可以破坏代码并弄乱它(使用反射,decompiling/modifying/recompiling,等等)。

附带说明一下,SecurityManager 的目的不是为了保护代码免受用户(例如 DRM 及其同类)的侵害,而是旨在保护用户免受代码的侵害。因此,这不是保护您的代码不被其他开发人员"misused"使用的有效方法。

更新

弃用是一个更复杂的问题。想一想有人使用你的代码一段时间的情况。理想情况下,他们应该能够升级到新版本而不修改他们的代码(假设新版本与旧版本合理兼容)。在这种情况下,如果已弃用的方法 "still works" 但不再是 "right way",您将不希望在以前工作的代码中开始抛出异常。但是,如果您已向用户发出大量警告,而现在此方法 根本不再有效 ,那么是的,您想要抛出异常。也就是说,如果您正在创建一个全新的 API 并且碰巧使用您不希望用户使用的已弃用方法公开 class,那么在这种情况下抛出异常也是合理的。

这里有一个后续的想法:如果您正在编写一个其他程序员将使用的库,那么与其试图对您的客​​户端隐藏您的线程,您应该反其道而行之:当您想要创建一个新的线程时线程,您应该允许您的客户为您创建它。

使用 ThreadFactory 实例创建新线程。

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();
    ...
}

如果客户端选择调用您的 setThreadFactory() 方法,那么您的代码将使用客户端的 ThreadFactory 实例来创建新线程。这给了客户端很大的权力来调试程序,记录线程创建事件,控制线程优先级,在线程组中组织线程,......所有这些都使你的模块更有用,对想要在一个大型程序,除了您的线程外,还有许多其他线程。

另一方面,如果您的客户选择不调用 setThreadFactory(),那么默认的 ThreadFactory 基本上只会为您调用 new Thread(r)