【问题标题】:java: how to set a global thread-ID?java:如何设置全局线程ID?
【发布时间】:2012-07-24 18:29:47
【问题描述】:

是否有可能为线程设置唯一 ID?在分布式系统中,线程是在许多不同的机器上创建的(例如通过 RMI)?

我需要它来创建日志消息。根据我的研究,我知道可以使用 log4j mdc/ndc 来完成,但只能在单线程中完成。我的问题是必须在创建线程时设置 ID(为不同 JVM 上的线程使用相同的 ID,但用于相同的请求)

我是分布式系统的新手。

【问题讨论】:

    标签: java multithreading log4j distributed


    【解决方案1】:

    如果您想拥有一个全局唯一的请求 id,您可以使用带有计数器的 prcoessAndName(见下文)并将其与您的消息/请求一起传递,并使用它来设置线程名称。

    public void processRequest(String uniqueRequestId, args) {
        Thread t = Thread.currrentThread();
        String tName = t.getName();
        try {
            t.setName("Processing " + uniqueRequestId);
            // preform process request
        } finally {
            t.setName(tName);
        }
    }
    

    这样,线程的名称将包含请求 ID,无论它在哪个线程/机器中运行。如果您在日志中包含线程的名称,它将被包含在内。


    您可以使用

    设置线程的名称
    String processAndHost = ManagementFactory.getRuntimeMXBean().getName()
    

    您可以在此附加一个描述性名称或计数器。

    这样你所有的线程名称都是唯一的。

    您可以假设此名称是全局唯一的,前提是 a) 您有一个唯一的主机名 b) 进程不会重新启动,因此经常存在两个客户端(在不同时间)具有相同进程 ID 的重大风险主机是个问题。

    这可以与本地唯一 id 结合,以获得分布式唯一 id。

    ExecutorService service = Executors.newCachedThreadPool(new ThreadFactory() {
        final String processName = ManagementFactory.getRuntimeMXBean().getName();
        final AtomicLong counter = new AtomicLong();
        @Override
        public Thread newThread(Runnable r) {
            String name = processName+"-"+counter.getAndIncrement();
            return new Thread(r, name);
        }
    });
    for(int i=0;i<10;i++)
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("["+Thread.currentThread().getName()+"] - Hello World.");
                Thread.yield();
            }
        });
    service.shutdown();
    

    打印

    [9480@myhost-0] - Hello World.
    [9480@myhost-3] - Hello World.
    [9480@myhost-2] - Hello World.
    [9480@myhost-1] - Hello World.
    [9480@myhost-5] - Hello World.
    [9480@myhost-4] - Hello World.
    [9480@myhost-6] - Hello World.
    [9480@myhost-7] - Hello World.
    [9480@myhost-0] - Hello World.
    [9480@myhost-7] - Hello World.
    

    【讨论】:

    • @Perter Lawrey - 我们可以使用这个唯一的名称跟踪从第一个线程到最后一个线程的请求吗?
    • 他不希望它们是全球唯一的,Peter,他希望它们在分布式请求中是全局的。没有答案,抱歉。
    • @trebuchet 祝你好运。这些天很难说出孩子们的穿着方式:-)
    • 如果您自己编写 RPC/messaging 库,您可以将其添加为字段并自动使用。如果您尝试使用标准 RMI,您唯一的选择是将其添加为对象中的字段或方法的参数。
    • @PeterLawrey 我使用 RMI。我想添加字段/参数是我需要的解决方案。
    【解决方案2】:

    你可以给线程一个名字(参见类java.lang.Thread的不同构造函数)。您可以为每个线程组成一个名称,例如计算机名称加上一个唯一编号。

    如果您正在使用例如ExecutorService 创建线程,那么您可以将ExecutorService 传递给您自己的java.util.concurrent.ThreadFactory 实现来创建线程并设置它们的名称。

    【讨论】:

    • 这是否意味着我可以为 threadB 设置一个相同的名称,它是由 threadA 在不同的 JVM 上自动创建的?
    • @trebuchet 不,他所说的没有任何暗示,或者任何接近它的东西。他没有回答你的实际问题,其他几个也没有。
    • @EJP 好的,那我理解起来有些困难。但是这样设置ID可以吗?
    【解决方案3】:

    您可以为线程设置名称,但不能设置/更改线程的 ID 来自 Thread 的 getId 方法的 java 文档

    http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#getId()

    "返回此线程的标识,线程ID是创建此线程时生成的一个正长整数,线程ID唯一,在其生命周期内保持不变。当线程终止时,该线程ID可能会被重用。”

    【讨论】:

      【解决方案4】:

      如果没有不可接受的线程创建开销,就没有。

      您应该通过请求 ID 或会话 ID 进行日志记录,而不是一些根本不存在的无法实现的全局线程 ID。

      我认为您需要对点击跟踪日志进行一些研究。

      【讨论】:

      • 这听起来很合理。但是线程可以识别是哪个请求创建的吗?或者请求 ID 应该与控制流一起使用吗?该怎么做?
      • 一旦请求进入系统,您就将其填充到日志记录 MDC 中。请求完成后,将其从 MDC 中删除。这样您就不必摆弄线程 ID。
      • @A.H.听起来不错!但是我不确定当请求经过很多线程时它是否可以工作。我认为只有一个请求=一个线程时,MDC 才能提供帮助。但如果我错了,这可能是一个很好的解决方案。
      • 如果请求真的是从一个线程传递到另一个线程,那么你就真的有问题了。然后每个接收线程都必须做 MDC 设置。这完全取决于您的框架 - 是否有一些中心位置可以保存或不做这些横切关注点 - 我们不知道。
      • @EJP 我已经开始我的研究了。但是当我尝试用谷歌搜索“clicktrack logging”时,我没有发现任何有用的东西。你知道任何例子或教程吗?
      猜你喜欢
      • 2010-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      相关资源
      最近更新 更多