如何在不使用 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)
。
与 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)
。