我有 2 个线程,每个线程都有一个名为 threadLocal 的 Threadlocal 列表,它们都将产生子线程。我希望子线程能够修改父线程的 threadLocal。
我尝试将父级本身传递给子级,以便它可以调用 parent.threadLocal.get().add(x) 但这会导致空指针异常。当父调用 threadLocal.get().add(x) 它能够将 x 添加到列表中就好了。
我知道问题出在 .add(x) 上,因为让孩子只调用 .get() 不会导致异常。我也尝试将 threadLocal 本身传递给孩子,这给出了同样的错误。
有没有办法做到这一点?
哪种方法更适合访问非线程安全对象?
使用ThreadLocal对象:
static final ThreadLocal<NonThreadSafeParser> PARSER_THREAD_LOCAL = new ThreadLocal<NonThreadSafeParser>() {
@Override
protected NonThreadSafeParser initialValue() {
return new NonThreadSafeParser();
}
};
void parse(String input) {
PARSER_THREAD_LOCAL.get().parse(input);
}
Run Code Online (Sandbox Code Playgroud)
使用并发对象池:
static final ConcurrentObjectPool<NonThreadSafeParser> PARSER_POOL = new ConcurrentObjectPool<>();
void parse(String input) {
NonThreadSafeParser parser = PARSER_POOL.borrow();
try {
parser.parse(input);
} finally {
PARSER_POOL.release(parser);
}
}
Run Code Online (Sandbox Code Playgroud)
或您想提供的其他方法?
重要因素是:
一般情况下,有什么优点和缺点的每个方法?
它们之间有什么明显的区别吗?
谢谢。
编辑:
正如我们所知,Tomcat 有大约 200 个线程,而 Jetty 在它们各自的线程池中有一些默认计数的线程。所以如果我们在ThreadLocal每个请求中设置一些东西,它会在线程中存在终生还是 Tomcat 会ThreadLocal在每个请求之后清除。
如果我们在过滤器的 userContext 中设置了一些东西,我们是否需要在过滤器每次退出时清除它?
或者如果我们没有线程池配置,Web 服务器是否每次都会创建一个新线程?
public static final ThreadLocal<UserContextDto> userContext = new ThreadLocal<>();
Run Code Online (Sandbox Code Playgroud) 我需要一个线程局部变量,理想情况下存储在一个结构中,该结构当前存储了我程序的大部分全局状态。
我可以看到的第一种方法是使用thread_local!宏,但是我想将此线程保留在我的状态结构中。
我可以看到实现这一点的第二种方法是HashMap<Thread,MyThreadLocalData>在线程和我的线程局部变量的值之间有一个或类似的。然后我将有一个thread::current用于查找适当值的吸气剂。
我应该提到的最后一个要求是,并非给定程序中的所有线程都是由 Rust 代码创建的,但是 Rust 代码可以在任何线程上运行,因此解决方案应该对此具有鲁棒性。
有没有这样做的最佳实践方法?也许有一个threadId可以让我使用简单Vec而不是一个HashMap(和/或避免散列开销)?有图书馆吗?
另一种选择是修改可以在多线程上下文中使用的每个函数的参数,以采用状态结构和线程本地状态结构,但是这对于不是由 Rust 创建的线程来说并不容易。
thread_local在我的代码中使用它之前,我想更好地理解它。
比方说,我声明
thread_local myclass value;
Run Code Online (Sandbox Code Playgroud)
这将为myclass每个使用value? 当线程退出时会发生什么?实例会被释放还是会保留在内存中的某个地方?什么时候会被称为析构函数?
是否thread_local锁定构造函数以便在任何时候都只能调用一个?
当使用 http 调用它们时,我想将从X-Request-IdNginx 接收到的信息传播到 k8s 中的其他服务。
现在,我正在使用请求过滤器来捕获该X-Request-Id标头并将其放入 MDC。
final String nginxRequestId = requestContext.getHeaderString("X-Request-Id");
if (nginxRequestId != null) {
MDC.put("infra_request", nginxRequestId);
}
Run Code Online (Sandbox Code Playgroud)
现在,我正在 k8s 内调用服务 B 的端点(因此没有 Nginx 的阻碍),我想获取它X-Request-Id以将其放入请求的标头中。我在这里可以看到两个选项:
我可能会使用 MDC 来完成此操作,但我不确定这是否是最佳实践,或者是否存在一些问题/问题。
使用 java 21,只需在虚拟线程中执行即可将阻塞 IO 代码转换为非阻塞代码。
我应该简单地包装返回 an 的 HTTP 调用InputStream(如 method 中),还是在虚拟线程中nonBlockingA执行 the 的读取和反序列化(如 method 中)会更有效?InputStreamnonBlockingB
也就是说,读取是InputStream阻塞IO操作吗?
请记住,响应可能非常大,可能包含超过 500,000 个字符串。我也不确定所使用的库是否使用任何 ThreadLocals,这不推荐用于虚拟线程
@SuppressWarnings("unchecked")
class Request {
private final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
private CloseableHttpClient httpApacheClient;
List<String> nonBlockingA() throws Exception {
InputStream bigInputStream = executorService.submit(this::getResponse).get();
return deserialize(bigInputStream);
}
List<String> nonBlockingB() throws Exception {
return executorService.submit(() -> {
InputStream bigInputStream = getResponse();
return deserialize(bigInputStream);
}).get();
}
private InputStream getResponse() throws IOException {
return httpApacheClient.execute(new HttpGet("http://random/names/size/500000")).getEntity().getContent(); …Run Code Online (Sandbox Code Playgroud) 我写了一个授权系统,它依赖于代表当前用户的对象.为了简化编程并提高性能,我希望在用户登录后将这些对象保存在ThreadLocal中.
它看起来像这样:
public class UserCache {
private static final ThreadLocal<User> cache = new ThreadLocal<User>();
public User getCurrentUser() {
return cache.get();
}
public void setCurrentUser(User user) {
cache.set(user);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经读过静态元素使聚类成问题.如果我在每个群集节点上都有一个UserCache,则它们都有自己的缓存对象与其他节点上的缓存对象不同步.对?UserCache是单例的经典候选者,因为应用程序只需要它的一个实例.但据我所知,@ Singleton EJB在集群中具有相同的行为.
那么如何使UserCache在EJB 3.1(Java EE 6)环境中可以集群?
从答案中提取的解决方案:
我有一个使用hibernate的web应用程序,由于某种原因,每个线程(httprequest或与排队相关的其他线程)使用不同的会话.我已经实现了一个HibernateSessionFactory看起来像这样的类:
public class HibernateSessionFactory {
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
private static Configuration configuration = new AnnotationConfiguration();
private static org.hibernate.SessionFactory sessionFactory;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
} catch (Exception e) {}
}
private HibernateSessionFactory() {}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();//This method basically does what the static init block does
}
session = …Run Code Online (Sandbox Code Playgroud) 我有一个类,我想声明一个私有成员,它是线程本地字典。这就是它的样子...
private static ThreadLocal<HashMap<Integer, Measurement>> measurements =
new ThreadLocal<HashMap<Integer, Measurement>>()
{
@Override protected HashMap<Integer, Measurement> initialValue()
{
return new HashMap<Integer, Measurement>();
}
};
Run Code Online (Sandbox Code Playgroud)
如您所见,我必须输入HashMap<Integer, Measurement>荒谬的次数。有什么办法可以使它更简洁?
thread-local ×10
java ×8
c++ ×1
concurrency ×1
destructor ×1
dropwizard ×1
ejb-3.0 ×1
hibernate ×1
inputstream ×1
java-21 ×1
java-ee ×1
mdc ×1
nonblocking ×1
performance ×1
rust ×1
session ×1
spring-boot ×1