多線程併發庫(一)

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]

多線程中共享數據

  1. 如果代碼塊執行的邏輯相同,可以在一個繼承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
  1. 如果代碼塊不同,就將數據封裝到同一個對象中,將這個對象逐一傳遞給每個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的應用

  1. 創建固定大小的線程池

    ExecutorService fixedThreadPools = Executors.newFixedThreadPool(5);

  2. 創建緩存線程池

    ExecutorService threadPools = (ExecutorService) 
                Executors.newCachedThreadPool();
    
  3. 創建單一線程池(保證內存中一直有一條線程)

    ExecutorService sigleThreadPools = Executors.newSingleThreadExecutor();

  4. 線程池啓動定時器

    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

  1. 通過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();
        }
    }
    }
    
  2. 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();
            }
        }
    }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章