深入研究 Java ThreadLocal
来源: Devgenios 今天您将了解 ThreadLocal,它是开发 Java 应用程序时使用的常用类之一。什么是ThreadLocal?
ThreadLocal类存储线程的局部变量。这些变量在不同线程之间是隔离的,只能被自己的线程访问。ThreadLocal的用例:- 隔离线程之间的数据。
- 数据库连接的会话管理。
- 存储线程事务信息。
如何使用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赋值并打印。输出时我们得到:
引擎盖下是什么?
如果你仔细观察,从这个代码示例中你可以看到ThreadLocal中有两个重要的方法。-
公共 T get() {}
-
public void set(T值){}
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实例,然后返回存储的值。这里有一个图表可以帮助您弄清楚:
-
每个线程都维护对ThreadLocalMap 的引用。
-
ThreadLocalMap是ThreadLocal的内部静态类,使用Entry类进行存储。
-
ThreadLocalMap键是ThreadLocal 的实例,可以有多个ThreadLocal。
-
ThreadLocal本身不存储值,但它是线程的关键,有助于从ThreadLocalMap获取值。
Java 中的扫描器类
来源:Medium 这篇文章将帮助您熟悉 Java 中的 Scanner 类。 Java中的Scanner类是我们想要从用户那里获取值时使用的类。理解它的最简单方法是通过示例,所以让我们更清楚地了解它。创建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);
基本上,我们重复前两行,询问用户该值并保存它。现在,在最后一行中,我们使用了从用户处获取的两个值,现在将它们一起使用。
GO TO FULL VERSION