多執行緒併發庫(一)
阿新 • • 發佈:2019-01-27
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(); } } }