該系列文章是博主學習筆記,禁止轉載,讀書交流羣: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 {
}