Java併發編程實戰(3)

該系列文章是博主學習筆記,禁止轉載,讀書交流羣:946541246

Java併發編程實戰五章學習

同步容器類的問題

public class UnsafeVectorHelpers {
    public static Object getLast(Vector list) {
        int lastIndex = list.size() - 1;
        return list.get(lastIndex);
    }

    public static void deleteLast(Vector list) {
        int lastIndex = list.size() - 1;
        list.remove(lastIndex);
    }
}

上面代碼存在的問題:如果線程A在包含10個元素的Vector上調用getLast,同時線程B在同一個Vector上調用deleteLast,就會出現ArrayIndexOutOfBoundsException異常
修復:使用客戶端加鎖,保證是一個原子操作

public class SafeVectorHelpers {
    public static Object getLast(Vector list) {
        synchronized (list) {
            int lastIndex = list.size() - 1;
            return list.get(lastIndex);
        }
    }

    public static void deleteLast(Vector list) {
        synchronized (list) {
            int lastIndex = list.size() - 1;
            list.remove(lastIndex);
        }
    }
}

同理下面程序也會出現問題
如果有其他線程併發地修改Vector時,則可能導致麻煩。
如果在對Vector進行迭代時,另一個線程刪除了一個元素,並且這兩個操作交替執行,那麼這種迭代方式將拋出ArrayIndexOutOfBoundsException異常

Vector vector = null;
        for (int i = 0; i < vector.size(); i++) {
            doSomething(vector.get(i));
        }

解決:

Vector vector = null;
        synchronized (vector) {
            for (int i = 0; i < vector.size(); i++) {
                doSomething(vector.get(i));
            }
        }

迭代器與ConcurrentModificationException

在for-each循環語法,對容器類進行迭代的標準方式都是使用Iterator。如果有其他線程併發地修改容器,會拋出ConcurrentModificationException異常。

List<Object> objects = Collections.synchronizedList(new ArrayList<Object>());
        // ...
        // 可能拋出ConcurrentModificationException
        for (Object o : objects) {
            //  doSomething
        }

要想避免出現ConcurrentModificationException,就必須在迭代過程中持有容器的鎖
如果容器的規模很大,或者在每個元素上執行操作的時間很長,那麼這些線程將長時間等待
如果不希望在迭代期間對容器加鎖,那麼一種替代方法就是“克隆”容器,在副本上進行迭代

toString、hashCode和equal等方法也會間接地執行迭代操作,當容器作爲另一個容器的元素或鍵值時,就會出現這種情況。同樣,containsAll、removeAll和retainAll等方法,以及把容器作爲參數的構造函數,都會對容器進行迭代。所有這些間接的迭代操作都可能拋出ConcurrentModificationException

阻塞方法與中斷方法

當代碼調用了一個將拋出InterruptedException異常的方法時,你自己的方法也就變成了一個阻塞方法,必須要處理對中斷的響應



import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class TaskRunnable implements Runnable {
    BlockingQueue<Task> queue = new LinkedBlockingQueue<>();

    public void run() {
        try {
            queue.put(new Task() {

            });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

            // 當代碼調用了一個將拋出InterruptedException異常的
            // 方法時,你自己的方法也就變成了一個阻塞方法,
            // 但這個方法並沒有阻塞住,
            // 但isInterrupted還是爲false,還是在調用下interrupt,
            // 讓它變成true吧
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    processTask(queue);
                } catch (InterruptedException e) {
                    System.out.println("TaskRunnable.run " + Thread.currentThread().isInterrupted());
                    Thread.currentThread().interrupt();
                    System.out.println("TaskRunnable.run " + Thread.currentThread().isInterrupted());
                }
            }

    }



    void processTask(BlockingQueue task) throws InterruptedException {
        System.out.println("TaskRunnable.processTask + " + task.take());
        throw new InterruptedException();
    }

    interface Task {
    }

    public static void main(String[] args) {
        TaskRunnable taskRunnable = new TaskRunnable();
        new Thread(taskRunnable).start();
    }
}

Java併發編程實戰六章學習

Executor框架

作用

將請求處理任務的提交與任務的實際執行解耦開來,並且只需採用另一種不同的Executor實現。

package unit6;

import java.util.concurrent.Executor;

/**
 * @program: JavaConcurrency
 * @description:
 * @create: 2020-01-04 14:44
 **/
public class ExecutorTest {

    public static void main(String[] args) {
        RunnableTest runnableTest = new RunnableTest();
        AsynchronousExecutor asynchronousExecutor = new AsynchronousExecutor();
        SynchronizationExecutor synchronizationExecutor = new SynchronizationExecutor();

        asynchronousExecutor.execute(runnableTest);
        synchronizationExecutor.execute(runnableTest);
    }

    /**
     * 異步
     */
    static class AsynchronousExecutor implements Executor {

        @Override
        public void execute(Runnable command) {
            new Thread(command).start();
        }
    }

    /**
     * 同步
     */
    static class SynchronizationExecutor implements Executor {

        @Override
        public void execute(Runnable command) {
            command.run();
        }
    }

    static class RunnableTest implements Runnable {

        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
}

Executor生命週期

public interface ExecutorService extends Executor {

	void shutdown();
	
	List<Runnable> shutdownNow();
	
	boolean isShutdown();
	
	boolean isTerminated();
	
	boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
        
    <T> Future<T> submit(Callable<T> task);
    
    <T> Future<T> submit(Runnable task, T result);
    
    Future<?> submit(Runnable task);
    
    List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;
        
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;
        
   <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;
   
   <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}	

ExecutorService 生命週期:運行、關閉、以終止

shutdown:執行平緩的關閉過程。不再接受新的任務,同時等待已經提交的任務執行完成——包括那些還未開始執行的任務

shutdownNow:取消所有運行中的任務,並且不再啓動隊列中尚未開始執行的任務

但shutdownNow無法通過常規方法找出哪些任務已經開始但尚未結束。無法在關閉過程中知道正在執行的任務的狀態

public class LifecycleWebServer {
    private final ExecutorService exec = Executors.newCachedThreadPool();

    public void start() throws IOException {
        ServerSocket socket = new ServerSocket(80);
        while (!exec.isShutdown()) {
            try {
                final Socket conn = socket.accept();
                exec.execute(new Runnable() {
                    public void run() {
                        handleRequest(conn);
                    }
                });
            } catch (RejectedExecutionException e) {
                if (!exec.isShutdown())
                    log("task submission rejected", e);
            }
        }
    }
}

使用ExecutorCompletionService提交一組任務

public abstract class Renderer {
    private final ExecutorService executor;

    Renderer(ExecutorService executor) {
        this.executor = executor;
    }

    void renderPage(CharSequence source) {
        final List<ImageInfo> info = scanForImageInfo(source);
        CompletionService<ImageData> completionService =
                new ExecutorCompletionService<ImageData>(executor);
        for (final ImageInfo imageInfo : info)
            completionService.submit(new Callable<ImageData>() {
                public ImageData call() {
                    return imageInfo.downloadImage();
                }
            });

        renderText(source);

        try {
            for (int t = 0, n = info.size(); t < n; t++) {
                Future<ImageData> f = completionService.take();
                ImageData imageData = f.get();
                renderImage(imageData);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            throw launderThrowable(e.getCause());
        }
    }

    interface ImageData {
    }

    interface ImageInfo {
        ImageData downloadImage();
    }

    abstract void renderText(CharSequence s);

    abstract List<ImageInfo> scanForImageInfo(CharSequence s);

    abstract void renderImage(ImageData i);

}

爲任務設置定時

public class RenderWithTimeBudget {
    private static final Ad DEFAULT_AD = new Ad();
    private static final long TIME_BUDGET = 1000;
    private static final ExecutorService exec = Executors.newCachedThreadPool();

    Page renderPageWithAd() throws InterruptedException {
        long endNanos = System.nanoTime() + TIME_BUDGET;
        Future<Ad> f = exec.submit(new FetchAdTask());
        // Render the page while waiting for the ad
        Page page = renderPageBody();
        Ad ad;
        try {
            // Only wait for the remaining time budget
            long timeLeft = endNanos - System.nanoTime();
            ad = f.get(timeLeft, NANOSECONDS);
        } catch (ExecutionException e) {
            ad = DEFAULT_AD;
        } catch (TimeoutException e) {
            ad = DEFAULT_AD;
            f.cancel(true);
        }
        page.setAd(ad);
        return page;
    }

    Page renderPageBody() { return new Page(); }


    static class Ad {
    }

    static class Page {
        public void setAd(Ad ad) { }
    }

    static class FetchAdTask implements Callable<Ad> {
        public Ad call() {
            return new Ad();
        }
    }

}

使用invokeAll提交一組限時任務

public class TimeBudget {
    private static ExecutorService exec = Executors.newCachedThreadPool();

    public List<TravelQuote> getRankedTravelQuotes(TravelInfo travelInfo, Set<TravelCompany> companies,
                                                   Comparator<TravelQuote> ranking, long time, TimeUnit unit)
            throws InterruptedException {
        List<QuoteTask> tasks = new ArrayList<QuoteTask>();
        for (TravelCompany company : companies)
            tasks.add(new QuoteTask(company, travelInfo));

        List<Future<TravelQuote>> futures = exec.invokeAll(tasks, time, unit);

        List<TravelQuote> quotes =
                new ArrayList<TravelQuote>(tasks.size());
        Iterator<QuoteTask> taskIter = tasks.iterator();
        for (Future<TravelQuote> f : futures) {
            QuoteTask task = taskIter.next();
            try {
                quotes.add(f.get());
            } catch (ExecutionException e) {
                quotes.add(task.getFailureQuote(e.getCause()));
            } catch (CancellationException e) {
                quotes.add(task.getTimeoutQuote(e));
            }
        }

        Collections.sort(quotes, ranking);
        return quotes;
    }

}

class QuoteTask implements Callable<TravelQuote> {
    private final TravelCompany company;
    private final TravelInfo travelInfo;

    public QuoteTask(TravelCompany company, TravelInfo travelInfo) {
        this.company = company;
        this.travelInfo = travelInfo;
    }

    TravelQuote getFailureQuote(Throwable t) {
        return null;
    }

    TravelQuote getTimeoutQuote(CancellationException e) {
        return null;
    }

    public TravelQuote call() throws Exception {
        return company.solicitQuote(travelInfo);
    }
}

interface TravelCompany {
    TravelQuote solicitQuote(TravelInfo travelInfo) throws Exception;
}

interface TravelQuote {
}

interface TravelInfo {
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章