Java中可以通過以下幾種方式來避免線程阻塞:
- 異步程式設計:使用異步程式設計可以避免線程阻塞,通過回調函數或者Future/Promise等方式來處理異步結果。
- 多線程并發:将任務拆分成多個子任務,使用多個線程并發執行,可以減少單個線程的阻塞時間。
- 非阻塞IO:使用NIO(New IO)等非阻塞IO方式,可以避免線程在IO操作時阻塞。
- 逾時機制:對于可能會阻塞的操作,可以設定逾時時間,逾時後自動結束操作,避免線程長時間阻塞。
- 線程池:使用線程池可以有效避免線程阻塞,通過線程池可控制線程的數量和執行順序,避免線程阻塞和資源浪費。
下面是一些具體例子
異步程式設計:
使用CompletableFuture實作異步程式設計:
CompletableFuture.supplyAsync(() -> {
// 異步執行的任務
return result;
}).thenAcceptAsync(result -> {
// 異步執行完後的回調函數
});
多線程并發:
使用ExecutorService實作多線程并發:
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i < 100; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
// 處理任務
}
});
}
executorService.shutdown();
非阻塞IO:
使用NIO實作非阻塞IO:
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(port));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.next();
if (selectionKey.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer);
buffer.flip();
socketChannel.write(buffer);
buffer.clear();
}
iterator.remove();
}
}
逾時機制:
使用Future和TimeUnit實作逾時機制:
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// 執行任務
return result;
}
});
try {
String result = future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
future.cancel(true);
e.printStackTrace();
}
逾時機制:
使用Future和TimeUnit實作逾時機制:
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
// 執行任務
return result;
}
});
try {
String result = future.get(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
future.cancel(true);
e.printStackTrace();
}
線程池:
使用ThreadPoolExecutor實作線程池:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
10, // 核心線程數
20, // 最大線程數
60, // 線程池空閑時間
TimeUnit.SECONDS, // 時間機關
new LinkedBlockingQueue<Runnable>(), // 任務隊列
new ThreadPoolExecutor.AbortPolicy() // 拒絕政策
);
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
// 處理任務
}
});
}
threadPoolExecutor.shutdown();
這個可以清晰的了解到阻塞、同步、異步的現象、概念和特征以及優缺點。有大量的案例可以快速了解每種通信架構的使用。
大廠面試之IO模式詳解(AIO,BIO,NIO)