标签: thread-local

ThreadLocal HashMap vs ConcurrentHashMap用于线程安全的未绑定缓存

我正在创建一个具有以下特征的memoization缓存:

  • 高速缓存未命中将导致计算和存储条目
    • 这个计算非常昂贵
    • 这种计算是幂等的
  • 无界限(条目从未删除),因为:
    • 输入将导致最多500个条目
    • 每个存储的条目都很小
    • 缓存相对短缺(通常不到一小时)
    • 总的来说,内存使用不是问题
  • 将有数千个读取 - 在缓存的生命周期中,我预计99.9%+缓存命中
  • 必须是线程安全的

什么会有一个优越的性能,或在什么条件下一个解决方案优于另一个解决方案?

ThreadLocal HashMap:

class MyCache {
    private static class LocalMyCache {
        final Map<K,V> map = new HashMap<K,V>();

        V get(K key) {
            V val = map.get(key);
            if (val == null) {
                val = computeVal(key);
                map.put(key, val);
            }
            return val;
        }
    }

    private final ThreadLocal<LocalMyCache> localCaches = new ThreadLocal<LocalMyCache>() {
        protected LocalMyCache initialValue() {
            return new LocalMyCache();
        }
    };

    public V get(K key) {
        return localCaches.get().get(key);
    }
}
Run Code Online (Sandbox Code Playgroud)

ConcurrentHashMap的: …

java performance caching concurrenthashmap thread-local

8
推荐指数
1
解决办法
1万
查看次数

为什么有些网络服务器会抱怨他们创建的内存泄漏?

标题可能有点强,但让我解释一下我是如何理解会发生什么的.我猜这发生在Tomcat上(引用的消息来自Tomcat),但我不确定了.

TL; DR在底部有一个总结,为什么我声称这是Web服务器的错.

我可能错了(但没有错误的可能性,没有理由问):

  • 应用程序使用库
  • 图书馆使用了 ThreadLocal
  • 所述ThreadLocal指物体从库
  • 每个对象指的是它 ClassLoader

网络服务器

  • 汇集其工作线程以提高效率
  • 为应用程序提供任意线程
  • 当应用程序停止或重新部署时,没有什么特别的(线程池)

如果我理解正确,重新部署后旧的"脏"线程继续被重用.它们ThreadLocal引用了引用它们的旧类,它们ClassLoader指的是整个旧的类层次结构.因此PermGen,随着时间的推移,很多东西都停留在空间中OutOfMemoryError.到目前为止这是对的吗?


我假设有两件事:

因此,在每次重新部署一个完整的线程池更新费一毫秒的一小部分几次每小时,也就是说,还有的时间开销0.0001 * 12/3600 * 100%,即0.000033%.

但是,不是接受这个微小的开销,而是有无数的问题.我的计算错了还是我忽略了什么?


作为警告,我们得到了消息

Web应用程序...使用类型为...的键创建了一个ThreadLocal,并且值为...但在Web应用程序停止时无法将其删除.

应该更好地说明

Web服务器...使用线程池但在停止(或重新部署)应用程序后无法续订.

还是我错了?即使所有线程不时重新创建,时间开销也可以忽略不计.但是ThreadLocal在将它们提供给应用程序之前清除它们就足够了,甚至更快.

摘要

有一些真正的问题(最近这个问题),用户无能为力.图书馆作家有时可以而且有时不能.恕我直言,网络服务器可以很容易地解决它.事情发生了并且有原因.所以我责怪唯一一个可以对此采取任何行动的政党.

关于Web服务器应该做什么的建议

这个问题的标题比正确的更具挑衅性,但它有其重点.raphw的答案也是如此.这个相关问题有另一个开放的赏金.

我认为Web服务器可以解决它如下:

  • 确保每个线程在某个时候被重用(或杀死)
  • LastCleanupTimestamp在a中存储a ThreadLocal(对于新线程,它是创建时间)
  • 重新使用线程时,检查清理时间戳是否低于某个阈值(例如,现在减去一些delta,例如1小时)
  • 如果是这样,清理所有ThreadLocals并设置一个新的LastCleanupTimestamp

这将确保没有这样的泄漏存在的时间长于delta加上最长请求的持续时间加上线程周转时间.费用如下:

  • ThreadLocal每个请求检查一个(即几纳秒) …

java webserver tomcat memory-leaks thread-local

8
推荐指数
1
解决办法
1118
查看次数

java.lang.Thread中的新增附加字段,有什么想法?

在Java 8中,java.lang.Thread类有3个新字段:

/** The current seed for a ThreadLocalRandom */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;

/** Probe hash value; nonzero if threadLocalRandomSeed initialized */
@sun.misc.Contended("tlr")
int threadLocalRandomProbe;

/** Secondary seed isolated from public ThreadLocalRandom sequence */
@sun.misc.Contended("tlr")
int threadLocalRandomSecondarySeed;
Run Code Online (Sandbox Code Playgroud)

正如它在Javadoc中所说的那样是由专门管理的java.util.concurrent.ThreadLocalRandom.

此外,ThreadLocalRandom它们以非常奇特的方式使用:

SEED = UNSAFE.objectFieldOffset
    (tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
    (tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
    (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
Run Code Online (Sandbox Code Playgroud)

(同样的代码片也可以在LockSupport课堂上得到满足).

然后这个偏移在几个java.concurrent地方内部使用.

这个想法是什么?为什么这些字段在里面java.lang.Thread?为什么不在里面ThreadLocalRandom

java thread-local java-8

8
推荐指数
1
解决办法
213
查看次数

将ThreadLocal与ExecutorService一起使用是危险的吗?

我在下面的博客上看到了ThreadLocals的概念:

https://www.baeldung.com/java-threadlocal

它说"不要将ThreadLocal与ExecutorService一起使用"

它说明了下面使用ThreadLocals的示例.

public class ThreadLocalWithUserContext implements Runnable {

    private static ThreadLocal<Context> userContext 
      = new ThreadLocal<>();
    private Integer userId;
    private UserRepository userRepository = new UserRepository();

    @Override
    public void run() {
        String userName = userRepository.getUserNameForUserId(userId);
        userContext.set(new Context(userName));
        System.out.println("thread context for given userId: "
          + userId + " is: " + userContext.get());
    }

    // standard constructor
}
Run Code Online (Sandbox Code Playgroud)

在帖子的最后,它提到:

"如果我们想使用ExecutorService并向其提交Runnable,那么使用ThreadLocal将产生非确定性结果 - 因为我们无法保证每次给定userId的每个Runnable操作都将由同一个线程处理执行.

因此,我们的ThreadLocal将在不同的userId之间共享.这就是为什么我们不应该将TheadLocal与ExecutorService一起使用.只有当我们完全控制哪个线程将选择要执行哪个可运行动作时,才应该使用它."

这个解释对我来说是一个保镖.我特意在网上做了一些研究,但是我得不到多少帮助,有些专家请详细说明上述解释吗?它是作者观点还是真正的威胁?

java multithreading thread-local

8
推荐指数
2
解决办法
1812
查看次数

内存问题和ThreadLocal <T>

我注意到这个ThreadLocal<T>实现IDisposable,暗示我在使用它时应该处理一个线程局部变量.我只是好奇具体的问题是什么,我应该小心做什么和/或避免做什么.

当线程退出时,线程的本地存储是否会被丢弃?如果我不处理我的ThreadLocal成员,最糟糕的情况是什么?

如果我有一个全局线程局部(oxymoron?hehe)变量(或者一个ThreadStatic变量)并且我在ThreadPool中的线程上赋值这个怎么办?我是否必须小心取消分配线程本地值,或者这不是一个问题?

.net c# multithreading thread-local

7
推荐指数
1
解决办法
2570
查看次数

ThreadLocal是否可以安全地与Tomcat NIO Connector一起使用

在负载测试期间测试Tomcat NIO连接器时,我们想到了这一点.我使用ThreadLocal另外我使用Spring,我知道在几个地方它也使用它.

由于NIO连接器每个连接没有一个线程,我担心如果ThreadLocal对象在清理之前与另一个线程共享,则可能导致很难找到错误.但是,我认为这不是一个问题,因为它不是我能找到的文件警告,也没有发现任何其他帖子警告这一点.我假设NIO连接器对服务于实际请求的线程没有影响.

在我采用这个假设之前,我希望找到一些具体的证据.

java tomcat nio thread-local

7
推荐指数
1
解决办法
2768
查看次数

ThreadLocal的使用如何降低可重用性

备受好评的书籍JCIP对ThreadLocal的使用说明了这一点:

通过将其线程限制属性视为使用全局变量的许可或作为创建"隐藏"方法参数的方法,很容易滥用ThreadLocal.线程局部变量可能会降低可重用性并在类之间引入隐藏的耦合,因此应谨慎使用.

说Thread-local变量可以减少可重用性并在类之间引入隐藏的耦合是什么意思?

java concurrency multithreading synchronization thread-local

7
推荐指数
1
解决办法
919
查看次数

关于使用ThreadLocals包装可变单例对象的建议

来自Java Concurrency in practice Chapter 3.3.3.ThreadLocal的

线程局部变量通常用于防止基于可变单元或全局变量的设计中的共享.

如果我们在ThreadLocal中包装可变的Singleton人,每个线程都有自己的Singleton副本?那么它将如何保持单身?这是作者的意思还是我错过了一些非常明显的东西?

java multithreading thread-local

7
推荐指数
1
解决办法
760
查看次数

线程本地的使用和需求是什么

我在Java中探索Thread本地.我无法理解为什么我们需要这门课.如果我只是简单地将一个新对象传递给每个线程来执行,我可以实现相同的动机,如果我使用initialValue()就会发生同样的事情.我只是在initialvalue()中为每个线程返回一个新对象.

但是说我有两个线程,ThreadOne:A和ThreadTwo B.现在我希望他们拥有自己的SimpleDateFormat类的副本.我可以通过在ThreadLocal类中扭曲SimpleDateFormat的对象然后使用initialValue()来执行此操作,我可以返回新的SimpleDateFormat("yyyyMMdd HHmm");. 同样的动机我可以通过创建两个新的SimpleDateFormat对象来实现,并且[每个都向ThreadOne提供一个:A.和ThreadTwo:B.ThreadLocal如何帮助我额外的

问候,

java multithreading thread-local

7
推荐指数
2
解决办法
1696
查看次数

ThreadLocal上的操作是否必须同步?

这是我偶然发现的代码:

class TransactionContextHolder {

private static final ThreadLocal<TransactionContext> currentTransactionContext = new NamedInheritableThreadLocal<TransactionContext>(
    "Test Transaction Context");


static TransactionContext getCurrentTransactionContext() {
    return currentTransactionContext.get();
}

static void setCurrentTransactionContext(TransactionContext transactionContext) {
    currentTransactionContext.set(transactionContext);
}

static TransactionContext removeCurrentTransactionContext() {
    synchronized (currentTransactionContext) {
        TransactionContext transactionContext = currentTransactionContext.get();
        currentTransactionContext.remove();
        return transactionContext;
    }
}
Run Code Online (Sandbox Code Playgroud)

}

所述currentTransactionContext字段是类型的ThreadLocal的,它是在该类中唯一的字段.

在我看来,这里不需要同步,因为存储在ThreadLocal中的值与特定线程相关联,因此它不是共享状态.另外我认为它会影响性能,因为currentTransactionContext本身是共享的,只允许一个线程进入块,而许多线程可以并行执行而不影响正确性.

这里需要同步吗?

java performance multithreading synchronized thread-local

7
推荐指数
1
解决办法
1477
查看次数