1. 程式人生 > >黑馬程式設計師多執行緒視訊總結

黑馬程式設計師多執行緒視訊總結

執行緒池的工作模型主要兩部分組成,一部分是執行Runnable的Thread物件,另一部分就是阻塞佇列。

由執行緒池建立的Thread物件其內部的run方法會通過阻塞佇列的take方法獲取一個Runnable物件,然後執行這個Runnable物件的run方法(即,在Thread的run方法中呼叫Runnable物件的run方法)。當Runnable物件的run方法執行完畢以後,Thread中的run方法又迴圈的從阻塞佇列中獲取下一個Runnable物件繼續執行。這樣就實現了Thread物件的重複利用,也就減少了建立執行緒和銷燬執行緒所消耗的資源。

當需要向執行緒池提交任務時會呼叫阻塞佇列的offer方法向佇列的尾部新增任務。提交的任務實際上就是是Runnable物件或Callable物件。

1.執行緒範圍共享變數

public class ThreadScopeShareData {

private static int data = 0;
private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
public static void main(String[] args) {
    for(int i=0;i<2;i++){
        new Thread(new Runnable(){
            @Override
            public void run() {
                int data = new Random().nextInt();
                System.out.println(Thread.currentThread().getName() 
                        + " has put data :" + data);
                //threadData.put(Thread.currentThread(), data);
                threadData.set(data);//這樣寫即可
                new A().get();
                new B().get();
            }
        }).start();
    }
}

static class A{
    public void get(){
        int data = threadData.get(Thread.currentThread());
        System.out.println("A from " + Thread.currentThread().getName() 
                + " get data :" + data);
    }
}

static class B{
    public void get(){
        int data = threadData.get(Thread.currentThread());          
        System.out.println("B from " + Thread.currentThread().getName() 
                + " get data :" + data);
    }       
}

}

2.TreadLocal實現執行緒範圍共享變數

public class ThreadLocalTest {
//一個TreadLocal只能代表一個變數,要是有多個數據需要線上程範圍共享就要有多個TreadLocal,或者弄成類
private static ThreadLocal x = new ThreadLocal();
private static ThreadLocal myThreadScopeData = new ThreadLocal();
public static void main(String[] args) {
for(int i=0;i<2;i++){
new Thread(new Runnable(){
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()
+ ” has put data :” + data);
x.set(data);

                /*MyThreadScopeData myData = new MyThreadScopeData();
                myData.setName("name" + data);
                myData.setAge(data);
                myThreadScopeData.set(myData);*/

                MyThreadScopeData.getThreadInstance().setName("name" + data);
                MyThreadScopeData.getThreadInstance().setAge(data);
                new A().get();
                new B().get();
            }
        }).start();
    }
}

static class A{
    public void get(){
        int data = x.get();
        System.out.println("A from " + Thread.currentThread().getName() 
                + " get data :" + data);

        /*MyThreadScopeData myData = myThreadScopeData.get();;
        System.out.println("A from " + Thread.currentThread().getName() 
                + " getMyData: " + myData.getName() + "," +
                myData.getAge());*/

        MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
        System.out.println("A from " + Thread.currentThread().getName() 
                + " getMyData: " + myData.getName() + "," +
                myData.getAge());
    }
}

static class B{
    public void get(){
        int data = x.get();         
        System.out.println("B from " + Thread.currentThread().getName() 
                + " get data :" + data);
        //得到當前執行緒的物件
        MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
        System.out.println("B from " + Thread.currentThread().getName() 
                + " getMyData: " + myData.getName() + "," +
                myData.getAge());           
    }       
}

}

class MyThreadScopeData{
//按照單例相似的去寫優雅的方式
private MyThreadScopeData(){}
//不用synchronized因為一個執行緒對應修改get set自己的變數
public static /synchronized/ MyThreadScopeData getThreadInstance(){
MyThreadScopeData instance = map.get();
if(instance == null){
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
}
//private static MyThreadScopeData instance = null;//new MyThreadScopeData();
private static ThreadLocal map = new ThreadLocal();

private String name;
private int age;
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;
}

}

3.多執行緒訪問共享物件和資料的方法
如果每個執行緒執行的程式碼相同,可用同一個Runnable物件,Runnable中由共享資料(例如賣票)
如果每個執行緒執行的程式碼不同,可將共享資料封裝在另一個物件中,然後將這個物件逐一傳遞給各Runnable

public class MultiThreadShareData {

private static ShareData1 data1 = new ShareData1();

public static void main(String[] args) {
    ShareData1 data2 = new ShareData1();
    new Thread(new MyRunnable1(data2)).start();
    new Thread(new MyRunnable2(data2)).start();

    final ShareData1 data1 = new ShareData1();
    new Thread(new Runnable(){
        @Ov  erride
        public void run() {
            data1.decrement();

        }
    }).start();
    new Thread(new Runnable(){
        @Override
        public void run() {
            data1.increment();

        }
    }).start();

}

}

class MyRunnable1 implements Runnable{
    private ShareData1 data1;
    public MyRunnable1(ShareData1 data1){
        this.data1 = data1;
    }
    public void run() {
        data1.decrement();

    }
}

class MyRunnable2 implements Runnable{
    private ShareData1 data1;
    public MyRunnable2(ShareData1 data1){
        this.data1 = data1;
    }
    public void run() {
        data1.increment();
    }
}

class ShareData1 /*implements Runnable*/{

/* private int count = 100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
count–;
}
}*/

    private int j = 0;
    public synchronized void increment(){
        j++;
    }

    public synchronized void decrement(){
        j--;
    }
}

java5之後:
4.原子類:AtomicInteger AtomicIntegerArray 。。。應用於多執行緒共享的資料

5.tomcat伺服器中
new Thread(){
while(池子中還有執行緒需要接待){
和執行緒聊一會;
}
}.start();

執行緒池
public class ThreadPoolTest {

public static void main(String[] args) {
    //ExecutorService threadPool = Executors.newFixedThreadPool(3); 固定數目的執行緒池,3個3個搶佔資源
    //ExecutorService threadPool = Executors.newCachedThreadPool(); 數目動態變化的執行緒池,來多少執行緒池多大
    ExecutorService threadPool = Executors.newSingleThreadExecutor();單一執行緒池,如何實現執行緒死了後重新啟動,當一個執行緒死了後,會馬上找一個替補的執行緒
    for(int i=1;i<=10;i++){
        final int task = i;
        threadPool.execute(new Runnable(){
            @Override
            public void run() {
                for(int j=1;j<=10;j++){
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " is looping of " + j + " for  task of " + task);
                }
            }
        });
    }
    System.out.println("all of 10 tasks have committed! ");
    //threadPool.shutdownNow();

    //定時器
    Executors.newScheduledThreadPool(3).scheduleAtFixedRate(
            new Runnable(){
                @Override
            public void run() {
                System.out.println("bombing!");

            }},
            6,
            2,
            TimeUnit.SECONDS);
}

}

6.
public class CallableAndFuture {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newSingleThreadExecutor();
Future future =
threadPool.submit( ——提交一個返回值
new Callable() {
public String call() throws Exception {
Thread.sleep(2000);
return “hello”;
};
}
);
System.out.println(“等待結果”);
try {
System.out.println(“拿到結果:” + future.get());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

    //CompletionService用於提交一組Callable任務,take方法返回已完成的Callable任務對應的furtuer物件
    ExecutorService threadPool2 =  Executors.newFixedThreadPool(10);
    CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool2);
    //提交10個任務
    for(int i=1;i<=10;i++){
        final int seq = i;
        completionService.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                Thread.sleep(new Random().nextInt(5000));
                return seq;
            }
        });
    }
    //拿到10個結果
    for(int i=0;i<10;i++){
        try {
            System.out.println(
                    completionService.take().get());
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ExecutionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

}

7.讀寫鎖:讀寫互斥,寫寫互斥,讀讀沒事
鎖比synchronized更加面向物件,必須要再結尾finnal中釋放鎖

public class ReadWriteLockTest {
public static void main(String[] args) {
final Queue3 q3 = new Queue3();
for(int i=0;i<3;i++)
{
new Thread(){
public void run(){
while(true){
q3.get();
}
}

        }.start();

        new Thread(){
            public void run(){
                while(true){
                    q3.put(new Random().nextInt(10000));
                }
            }           

        }.start();
    }

}

}

class Queue3{
private Object data = null;//共享資料,只能有一個執行緒能寫該資料,但可以有多個執行緒同時讀該資料。
ReadWriteLock rwl = new ReentrantReadWriteLock();
public void get(){
rwl.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + ” be ready to read data!”);
Thread.sleep((long)(Math.random()*1000));
System.out.println(Thread.currentThread().getName() + “have read data :” + data);
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock();
}
}

public void put(Object data){

    rwl.writeLock().lock();
    try {
        System.out.println(Thread.currentThread().getName() + " be ready to write data!");                  
        Thread.sleep((long)(Math.random()*1000));
        this.data = data;       
        System.out.println(Thread.currentThread().getName() + " have write data: " + data);                 
    } catch (InterruptedException e) {
        e.printStackTrace();
    }finally{
        rwl.writeLock().unlock();
    }


}

}

8.模擬快取
這樣寫讀寫效率高
public class CacheDemo {
//內部定義一個map
private Map