JavaRush /Java 博客 /Random-ZH /喝咖啡休息#160。深入研究 Java ThreadLocal。Java 中的扫描器类

喝咖啡休息#160。深入研究 Java ThreadLocal。Java 中的扫描器类

已在 Random-ZH 群组中发布

深入研究 Java ThreadLocal

来源: Devgenios 今天您将了解 ThreadLocal,它是开发 Java 应用程序时使用的常用类之一。 喝咖啡休息#160。 深入研究 Java ThreadLocal。 Java 中的扫描器类 - 1

什么是ThreadLocal?

ThreadLocal类存储线程的局部变量。这些变量在不同线程之间是隔离的,只能被自己的线程访问。ThreadLocal的用例:
  1. 隔离线程之间的数据。
  2. 数据库连接的会话管理。
  3. 存储线程事务信息。

如何使用ThreadLocal?

让我们看一个简单的例子。
public static void main(String[] args) {
    //Создаем ThreadLocal
    ThreadLocal<String> local = new ThreadLocal<>();
    //Создаем новый класс Random
    Random random = new Random();
    //Создаем 5 потоков
    IntStream.range(0, 5).forEach(a-> new Thread(()-> {
        //Присваиваем meaning каждому потоку
        local.set(a+"  "+random.nextInt(100));
        System.out.println("Thread number and its local value  "+ local.get());
    }).start());
}
上面的代码中,我们创建了一个ThreadLocal类,创建了5个线程,在每个线程中给ThreadLocal赋值并打印。输出时我们得到: 喝咖啡休息#160。 深入研究 Java ThreadLocal。 Java 中的扫描器类 - 2

引擎盖下是什么?

如果你仔细观察,从这个代码示例中你可以看到ThreadLocal中有两个重要的方法。
  • 公共 T get() {}

  • public void set(T值){}

我们看一下ThreadLocal源码中的setter方法:
public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
}
setter 方法首先获取当前线程,并调用getMap()方法获取ThreadLocalMap类。如果map存在,则以当前流t为key,输入参数为value,将{key:value}对设置为map。如果没有,则创建一个地图。现在你可能有一个问题 - 什么是ThreadLocalMap
static class ThreadLocalMap {
   /**
    * The entries in this hash map extend WeakReference, using
    * its main ref field as the key (which is always a
    * ThreadLocal object).  Note that null keys (i.e. entry.get()
    * == null) mean that the key is no longer referenced, so the
    * entry can be expunged from table.  Such entries are referred to
    * as "stale entries" in the code that follows.
    */
    static class Entry extends WeakReference<ThreadLocal<?>> {
       /** The value associated with this ThreadLocal. */
       Object value;
       Entry(ThreadLocal<?> k, Object v) {
           super(k);
           value = v;
       }
    }
}
ThreadLocalMap是ThreadLocal中的一个内部静态类,它定义了一个Entry类来存储数据。Entry使用ThreadLocal实例作为键并设置我们传递的值。如果这听起来太令人困惑,请记住,实际存储值的是ThreadLocalMap中的Entry类。为了从ThreadLocal获取数据,我们使用getter方法:
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
}
getter方法中,我们将使用currentThread作为键来获取ThreadLocalMap。然后map会根据ThreadLocal实例getEntry()并返回Entry实例,然后返回存储的值。这里有一个图表可以帮助您弄清楚: 喝咖啡休息#160。 深入研究 Java ThreadLocal。 Java 中的扫描器类 - 3喝咖啡休息#160。 深入研究 Java ThreadLocal。 Java 中的扫描器类 - 4
  1. 每个线程都维护对ThreadLocalMap 的引用。

  2. ThreadLocalMap是ThreadLocal的内部静态类,使用Entry类进行存储。

  3. ThreadLocalMap键是ThreadLocal 的实例,可以有多个ThreadLocal

  4. ThreadLocal本身不存储值,但它是线程的关键,有助于从ThreadLocalMap获取值。

请注意,最好删除ThreadLocal,以避免由于Entry类中的“弱”引用而导致 OOM(内存不足错误)。

Java 中的扫描器类

来源:Medium 这篇文章将帮助您熟悉 Java 中的 Scanner 类。 Java中的喝咖啡休息#160。 深入研究 Java ThreadLocal。 Java 中的扫描器类 - 5Scanner类是我们想要从用户那里获取值时使用的类。理解它的最简单方法是通过示例,所以让我们更清楚地了解它。创建Scanner类是我们从用户那里获取值所采取的三个步骤之一。第一步是从扫描仪类创建一个对象。
Scanner scan=new Scanner(System.in);
现在我们有一个扫描仪对象。该对象将具有Scanner类的 Scanner 属性。第一步之后,用户已经可以输入想要的值,但是如果我们不引导用户并在控制台或应用程序中显示该值,那么在可用性方面就不会很好。因此,最好告知并指导用户:
System.out.println("Please enter your name");
String name=scan.next();
System.out.println("Your Name:"+name);
在第一行中,我们询问用户我们想从他那里得到什么。这实际上与扫描仪无关,但向用户提供提示总是好的。在第二行中,我们将分配用户输入数据的值并保存它,以便稍后使用。在最后一行中,我们看到我们可以自行决定使用从用户那里收到的值。让我们在代码中添加更多细节:
System.out.println("Please enter your last name");

String lastName=scan.next();

System.out.println("Your Name " + name + " " + "Your Last Name" + lastName);
基本上,我们重复前两行,询问用户该值并保存它。现在,在最后一行中,我们使用了从用户处获取的两个值,现在将它们一起使用。
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION