ThreadLocal
是线程局部变量。在多线程中,实现每个线程中变量的私有性。
例子一
在该例子中,在同一个线程中通过调用类A和类B的getData()方法获取的数据是一致的。
public class ThreadLocalTest {
static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
final ThreadLocalTest tlt = new ThreadLocalTest();
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
threadLocal.set(data);
System.out.println(Thread.currentThread().getName()+"==生成的数据是:"+data);
tlt.new A().getData();
tlt.new B().getData();
}
}).start();
}
}
class A{
public void getData(){
System.out.println(Thread.currentThread().getName()+"A:"+"取出的数据是:"+threadLocal.get());
}
}
class B{
public void getData(){
System.out.println(Thread.currentThread().getName()+"B:"+"取出的数据是:"+threadLocal.get());
}
}
** }
结果:**
Thread-1==生成的数据是:-229198565
Thread-2==生成的数据是:-1892334218
Thread-0==生成的数据是:-1126013147
Thread-0A:取出的数据是:-1126013147
Thread-1A:取出的数据是:-229198565
Thread-2A:取出的数据是:-1892334218
Thread-1B:取出的数据是:-229198565
Thread-2B:取出的数据是:-1892334218
Thread-0B:取出的数据是:-1126013147
例子二
实现每个线程只拥有一个实例对象的写法。
public class ThreadLocalForObjTest {
static ThreadLocal<Student> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
final ThreadLocalForObjTest tlt = new ThreadLocalForObjTest();
for(int i=0;i<3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt(150);
Student s = Student.getInstance();
s.setAge(data);
s.setName("lzl"+data);
threadLocal.set(s);
System.out.println(Thread.currentThread().getName()+"==生成的数据是:"+data);
tlt.new A().getData();
tlt.new B().getData();
}
}).start();
}
}
class A{
public void getData(){
System.out.println(Thread.currentThread().getName()+"A:"+"取出的数据是:"+threadLocal.get().toString());
}
}
class B{
public void getData(){
System.out.println(Thread.currentThread().getName()+"B:"+"取出的数据是:"+threadLocal.get().toString());
}
}
}
class Student{
private String name;
private int age;
private static ThreadLocal<Student> map = new ThreadLocal<Student>();
public static Student getInstance(){
Student instance = map.get();
if(instance ==null){
instance = new Student();
map.set(instance);
System.out.println("======显示次数========");
}
return instance;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
结果
三个线程,创建了三个实例对象。并且保证单个线程中的数据是私有的。
======显示次数========
======显示次数========
======显示次数========
Thread-0==生成的数据是:81
Thread-1==生成的数据是:67
Thread-2==生成的数据是:81
Thread-2A:取出的数据是:Student [name=lzl81, age=81]
Thread-0A:取出的数据是:Student [name=lzl81, age=81]
Thread-1A:取出的数据是:Student [name=lzl67, age=67]
Thread-1B:取出的数据是:Student [name=lzl67, age=67]
Thread-0B:取出的数据是:Student [name=lzl81, age=81]
Thread-2B:取出的数据是:Student [name=lzl81, age=81]
多线程中共享数据
如果代码块执行的逻辑相同,可以在一个继承Runnable的类中实现数据的共享。
两个线程之间共享了count数据public class MultiThreadShareData { public static void main(String[] args) { MyRunnable mr = new MyRunnable(); new Thread(mr).start(); new Thread(mr).start(); } static class MyRunnable implements Runnable{ private int count=5; @Override public void run() { while(true){ System.out.println("线程名:"+Thread.currentThread().getName()+" count="+count); if(count<1){ break; } dec(); } } private synchronized int dec(){ count--; return count; } } }
结果:
线程名:Thread-0 count=5
线程名:Thread-1 count=5
线程名:Thread-0 count=4
线程名:Thread-1 count=3
线程名:Thread-1 count=1
线程名:Thread-0 count=2
线程名:Thread-1 count=0
如果代码块不同,就将数据封装到同一个对象中,将这个对象逐一传递给每个Runnable对象。
两个线程之间共享了data数据public class MultiThreadShareData2 { public static void main(String[] args) { new MultiThreadShareData2().init(); } private void init(){ new Thread(new DecRunnable(this)).start(); new Thread(new IncRunnable(this)).start(); } int data=10; private synchronized void dec(){ data--; System.out.println(Thread.currentThread().getName()+" data Dec="+data); } private synchronized void inc(){ data++; System.out.println(Thread.currentThread().getName()+" data Inc="+data); } static class DecRunnable implements Runnable{ private MultiThreadShareData2 data; public DecRunnable(MultiThreadShareData2 data2){ this.data = data2; } @Override public void run() { while(true){ data.dec(); } } } static class IncRunnable implements Runnable{ private MultiThreadShareData2 data; public IncRunnable(MultiThreadShareData2 data2){ this.data = data2; } @Override public void run() { while(true){ data.inc(); } } } }
Executors的应用
创建固定大小的线程池
ExecutorService fixedThreadPools = Executors.newFixedThreadPool(5);
创建缓存线程池
ExecutorService threadPools = (ExecutorService) Executors.newCachedThreadPool();
创建单一线程池(保证内存中一直有一条线程)
ExecutorService sigleThreadPools = Executors.newSingleThreadExecutor();
线程池启动定时器
ScheduledExecutorService threadPools = (ScheduledExecutorService) Executors.newScheduledThreadPool(3); //创建一个计时器的线程 threadPools.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("hhh"); } }, 2, 2, TimeUnit.SECONDS); }
例子:
public class ExecutorsTest { public static void main(String[] args) { ExecutorService threadPools = (ExecutorService) Executors.newCachedThreadPool();//创建缓存线程池。线程的大小没有固定 ExecutorService fixedThreadPools = Executors.newFixedThreadPool(5);//创建固定大小的线程池 ExecutorService sigleThreadPools = Executors.newSingleThreadExecutor();//创建 for(int i=0;i<10;i++){ final int task = i; fixedThreadPools.execute(new Runnable() { @Override public void run() { for(int i=0;i<10;i++){ System.out.println("线程名:"+Thread.currentThread().getName()+" 循环了"+i+"次,第"+task+"任务"); } } }); } System.out.println("循环结束..."); new ExecutorsTest().hh(); }
Callable和Future
通过Executors的submit方法获取线程中返回的结果。
public class CallableAndFuture { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(2000); return "Hello Thread!"; } }; Future<String> future = executorService.submit(callable); System.out.println("等待结果..."); try { System.out.println("结果是:"+future.get(1,TimeUnit.SECONDS)); //1s后没有拿到结果,就抛错! } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } }
CompletionService提交多组数据
private void futureTest2(){ ExecutorService executorService = Executors.newFixedThreadPool(5); CompletionService<Integer> completionService = new ExecutorCompletionService(executorService); for(int i=0;i<10;i++){ final int task=i; completionService.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { Thread.sleep(new Random().nextInt(5000)); return task; } }); } for(int i=0;i<10;i++){ try { System.out.println("结果是:"+completionService.take().get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }