防止任务在共享资源上发生冲突的一种方式是根除对变量的共享。线程本地存储可以为使用相同变量的每个不同线程都创建不同存储。ThreadLocal该类提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
例如,以下类生成对每个线程唯一的局部标识符。线程 ID 是在第一次调用 UniqueThreadIdGenerator.getCurrentThreadId() 时分配的,在后续调用中不会更改。
package concurrent;
import java.util.concurrent.atomic.AtomicInteger;
public class UniqueThreadIdGenerator {
private static final AtomicInteger uniqueId = new AtomicInteger(0);
private static final ThreadLocal<Integer> uniqueNum = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return uniqueId.getAndIncrement();
}
};
public static int getCurrentThreadId() {
return uniqueNum.get();
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(UniqueThreadIdGenerator
.getCurrentThreadId());
}
}).start();
}
}
} // UniqueThreadIdGenerator
输出结果:
0
2
4
3
1
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且 ThreadLocal 实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)。
下面演示了创建和管理本地存储由ThreadLocal实现的一个简单实例。get返回与线程相关联的对象副本,set会将参数插入到为其线程存储的对象中,并返回原有的对象。
package concurrency;
//: concurrency/ThreadLocalVariableHolder.java
// Automatically giving each thread its own storage.
import java.util.concurrent.*;
import java.util.*;
class Accessor implements Runnable {
private final int id;
public Accessor(int idn) {
id = idn;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
ThreadLocalVariableHolder.increment();
System.out.println(this);
Thread.yield();
}
}
public String toString() {
return "#" + id + ": " + ThreadLocalVariableHolder.get();
}
}
public class ThreadLocalVariableHolder {
private static ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
private Random rand = new Random(47);
// initialValue返回此线程局部变量的当前线程的“初始值”。线程第一//次使用 get()
// 方法访问变量时将调用此方法,但如果线程之前调用了 set(T)
// 方法,则不会对该线程再调用 initialValue 方法。通常,此方法对每//个线程最多调用一次,但如果在调用 get() 后又调用了
// remove(),则可能再次调用此方法。
// 该实现返回 null;如果程序员希望线程局部变量具有 null 以外的
//值,则必须为 ThreadLocal
// 创建子类,并重写此方法。通常将使用匿名内部类完成此操作
@Override
protected synchronized Integer initialValue() {
return rand.nextInt(10000);
}
};
public static void increment() {
value.set(value.get() + 1);
}
public static int get() {
return value.get();
}
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++)
exec.execute(new Accessor(i));
TimeUnit.SECONDS.sleep(1); // Run for a while
exec.shutdownNow(); // All Accessors will quit
}
}
输出结果:
#1: 556
#3: 962
#0: 9259
#2: 1862
#4: 6694
欢迎交流。
分享到:
相关推荐
10. **线程本地存储(ThreadLocal)**:为每个线程提供独立的变量副本,避免了线程间的共享数据冲突。 11. **并发集合**:如ConcurrentHashMap、CopyOnWriteArrayList等,这些集合类在并发环境下提供了高性能的读写...
线程本地存储,如 `ThreadLocal` 类,提供了线程安全的数据结构,使得每个线程拥有自己的副本,避免了数据竞争问题。 #### 四、Java线程:线程状态的转换 - **线程的状态** Java线程的状态包括新建 (`NEW`)、...
* 每个线程都拥有单独的栈内存用来存储本地数据 三、如何在 Java 中实现线程? * Java 在语言层面对多线程提供了卓越的支持 * 有两种方式可以实现线程:继承 Thread 类或实现 Runnable 接口 * 通过继承 Thread 类...
这通常需要在本地存储文件元数据,包括每个部分的开始和结束位置。 以上就是Java多线程下载器的主要技术点。实现这样一个下载器,不仅锻炼了对Java多线程的理解,还涉及到网络编程、文件操作以及并发控制等多个方面...
2. **线程安全的数据结构**:为了确保线程安全,可以使用Java的并发集合,如`ConcurrentHashMap`、`BlockingQueue`等,它们内部已经处理了多线程环境下的并发问题。 3. **线程间通信**:有时需要线程间传递信息,...
Java 线程本地变量 ThreadLocal 详解 ThreadLocal 是 Java 中的一个类,提供了线程安全的对象封装,用于解决多线程访问数据的冲突问题。ThreadLocal 的主要目的是为每个线程提供一个变量副本,从而隔离了多个线程...
线程本地存储(ThreadLocal)提供了线程内部的局部变量,这些变量对其他线程而言是隔离的。在多线程环境下,ThreadLocal可以用来存储线程特有对象,避免使用全局变量,从而提供线程安全。 线程阻塞是指线程在某些...
在Java中,线程是程序执行的最小单元,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈和一部分堆内存。Java提供两种创建线程的方式:继承Thread类或实现Runnable接口。创建线程后,可以调用start()方法启动...
Java线程-Java内存模型是Java并发编程中的关键概念,它描述了多个线程如何共享和访问内存资源,以及如何保证数据的一致性和安全性。Java内存模型(JMM)是Java虚拟机规范的一部分,用于定义程序中各个线程对共享变量...
它不仅考验开发者对Java编程、多线程处理、网络通信以及数据存储等技术的掌握,还要求对爬虫算法、网页结构有深刻理解,同时需关注爬虫的伦理与法律规定。通过精心设计和不断优化,可以构建出高效、稳定的网络爬虫...
Java程序中的多线程技术是实现并发操作的关键,尤其在处理并发读写数据时,如在本例中,我们有两条线程分别负责读取和写入学生的成绩...通过学习这个程序,我们可以深入理解Java线程的使用以及并发编程中的核心概念。
### Java线程迁移机制的研究 #### 一、引言 随着Java移动代理技术和集群技术的发展,Java线程迁移成为了一个重要的研究领域。线程迁移在Java移动代理系统中用于将代理线程从一个节点转移到另一个节点,在Web包容器...
线程是程序执行的最小单元,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈,而它们共享堆内存和静态存储区。Java中的Thread类提供了创建和管理线程的方法。 1. 继承Thread类:创建一个新的类,该类继承自...
通过本教程的学习,你已经掌握了Java线程的基础知识,并了解了如何使用线程来优化程序性能和用户体验。接下来,你可以进一步深入学习更高级的线程管理和控制技术,以便更好地应对实际项目中的并发挑战。
4. **下载与保存**:每个线程负责下载分配给它的那一部分文件,并将其保存到本地硬盘的相应位置。线程之间独立运行,互不影响。 5. **合并文件**:所有线程完成下载后,将各部分合并成完整的文件。由于使用了`...
每个线程都有自己独立的栈内存来存储本地数据。 知识点3:Java中实现线程的两种方式 Java中可以通过继承java.lang.Thread类或实现java.lang.Runnable接口来实现线程。Thread类的实例本身就是线程,而Runnable是一个...
本文将详细介绍如何使用Java实现基于Socket的多线程非同步网络文件传输。 #### 关键技术点 1. **Socket通信**:Socket是实现网络通信的基础组件,它提供了一种在网络间进行双向数据传输的方式。在Java中,可以使用...
在"C++使用JNI多线程回调java代码例子"中,虽然具体实现没有提供,但我们可以想象一个典型流程: 1. **初始化JNIEnv**:在C++中,我们需要获取到`JNIEnv`指针,这是JNI的核心,提供了调用Java方法和访问Java对象的...
- **同步机制**:为了保证文件下载后的完整性,需要使用Java的同步机制,如`synchronized`关键字、`Lock`接口等,确保线程间对同一资源的访问是有序的。 - **信号量(Semaphore)**:当某一线程下载完其负责的部分...