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(); } } }