关于ThreadLocal如何保证数据线程安全
展开全部
ThreadLocal的核心概念是没一个线程可以通过get或者set方法访问它自己的、独立初始化的变量的副本。
1. ThreadLocal介绍
为了在多线程环境下不出现任何的冲突,我们希望能否分离一个类的多个实例。对于每一个线程来说,没一个实例都是唯一的。这不过是实现线程安全的一个方式。
线程安全的另外的重要的一点是能够全局访问。可以在线程内部的任何地方进行访问。记住:应该声明成static和final的。
2. 什么是线程安全
线程是进程的一条单独的线。当我们提到多线程应用的时候,我们的意思是一个进程的多个线程访问同一行代码。在这个情况下,存在一个线程访问或者修改另一个线程的数据的可能性。当数据不允许这样共享的时候,我们应该做成线程安全的。实现线程安全的方式有下面几种:
· 重入
·互斥(同步机制)
·ThreadLocal
·原子操作
3. 使用ThreadLocal
(引用Joshua Bloch的一段话,巨抽象,我没看懂,......)
我们有一个非线程安全的变量,我们想把它变成线程安全的,可以考虑同步机制把对象封闭到同步块中。另外的方式是使用ThreadLocal,为每一个线程持有单独的对象使得变得安全。
4. ThreadLocal的例子
package com.javapapers;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ThreadLocalExample {
private static final ThreadLocal formatter = new ThreadLocal() {
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public String formatIt(Date date) {
return formatter.get().format(date);
}
}
上边的代码中,关键要理解get()方法。他返回的当前线程的ThreadLocal变量的副本。如果当前线程的这个变量还没有值,则通过调用initalValue方法返回第一次初始化的值。
JavaDoc中的例子
下面的例子为每一个线程生成一个唯一的标识符。第一次调用get方法的时候指定一个线程的id,并且在随后的调用中保持不变。
port java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal threadId =
new ThreadLocal() {
@Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
5. Java API中ThreadLocal 的使用
在JDK1.7中,我们有一个叫做ThreadLocalRandom的新类。它用于为并行的线程生成随机数,每一个线程是随机数的种子都是唯一的。这是一个非常酷的功能。
下面的代码是上边的类实现ThreadLocal 的代码:
private static final ThreadLocal localRandom =
new ThreadLocal() {
protected ThreadLocalRandom initialValue() {
return new ThreadLocalRandom();
}
};
使用ThreadLocalRandom
package com.javapapers;
import java.util.concurrent.ThreadLocalRandom;
public class ThreadLocalRandomExample {
public static void main(String args[]) throws InterruptedException {
//tossing 3 coins
for (int i = 0; i < 3; i++) {
final Thread thread = new Thread() {
public void run() {
System.out.print(Thread.currentThread().getName() + ":");
// generating 3 random numbers - random for every thread
for (int j = 0; j < 3; j++) {
final int random = ThreadLocalRandom.current().nextInt(
1, 3);
System.out.print(random + ",");
}
System.out.println();
}
};
thread.start();
thread.join();
}
}
}
6. ThreadLocal和内存泄露
ThreadLocal不是一个魔鬼,而是一个优秀的、实用的API。完全取决于我们怎么样去使用。我们应该学会在正确的场合使用合适的工具。我们不能使用大炮打蚊子,但是也不能谴责大炮。
1. ThreadLocal介绍
为了在多线程环境下不出现任何的冲突,我们希望能否分离一个类的多个实例。对于每一个线程来说,没一个实例都是唯一的。这不过是实现线程安全的一个方式。
线程安全的另外的重要的一点是能够全局访问。可以在线程内部的任何地方进行访问。记住:应该声明成static和final的。
2. 什么是线程安全
线程是进程的一条单独的线。当我们提到多线程应用的时候,我们的意思是一个进程的多个线程访问同一行代码。在这个情况下,存在一个线程访问或者修改另一个线程的数据的可能性。当数据不允许这样共享的时候,我们应该做成线程安全的。实现线程安全的方式有下面几种:
· 重入
·互斥(同步机制)
·ThreadLocal
·原子操作
3. 使用ThreadLocal
(引用Joshua Bloch的一段话,巨抽象,我没看懂,......)
我们有一个非线程安全的变量,我们想把它变成线程安全的,可以考虑同步机制把对象封闭到同步块中。另外的方式是使用ThreadLocal,为每一个线程持有单独的对象使得变得安全。
4. ThreadLocal的例子
package com.javapapers;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ThreadLocalExample {
private static final ThreadLocal formatter = new ThreadLocal() {
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public String formatIt(Date date) {
return formatter.get().format(date);
}
}
上边的代码中,关键要理解get()方法。他返回的当前线程的ThreadLocal变量的副本。如果当前线程的这个变量还没有值,则通过调用initalValue方法返回第一次初始化的值。
JavaDoc中的例子
下面的例子为每一个线程生成一个唯一的标识符。第一次调用get方法的时候指定一个线程的id,并且在随后的调用中保持不变。
port java.util.concurrent.atomic.AtomicInteger;
public class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal threadId =
new ThreadLocal() {
@Override protected Integer initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
5. Java API中ThreadLocal 的使用
在JDK1.7中,我们有一个叫做ThreadLocalRandom的新类。它用于为并行的线程生成随机数,每一个线程是随机数的种子都是唯一的。这是一个非常酷的功能。
下面的代码是上边的类实现ThreadLocal 的代码:
private static final ThreadLocal localRandom =
new ThreadLocal() {
protected ThreadLocalRandom initialValue() {
return new ThreadLocalRandom();
}
};
使用ThreadLocalRandom
package com.javapapers;
import java.util.concurrent.ThreadLocalRandom;
public class ThreadLocalRandomExample {
public static void main(String args[]) throws InterruptedException {
//tossing 3 coins
for (int i = 0; i < 3; i++) {
final Thread thread = new Thread() {
public void run() {
System.out.print(Thread.currentThread().getName() + ":");
// generating 3 random numbers - random for every thread
for (int j = 0; j < 3; j++) {
final int random = ThreadLocalRandom.current().nextInt(
1, 3);
System.out.print(random + ",");
}
System.out.println();
}
};
thread.start();
thread.join();
}
}
}
6. ThreadLocal和内存泄露
ThreadLocal不是一个魔鬼,而是一个优秀的、实用的API。完全取决于我们怎么样去使用。我们应该学会在正确的场合使用合适的工具。我们不能使用大炮打蚊子,但是也不能谴责大炮。
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询