真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java異步接口代碼 java異步代碼塊

如何用Java回調(diào)和線程實現(xiàn)異步調(diào)用

軟件模塊之間的調(diào)用關(guān)系可以分為兩大類:即同步調(diào)用和異步調(diào)用。在同步調(diào)用中,一段代碼(主調(diào)方)調(diào)用另一段代碼(被調(diào)方),主調(diào)方必須等待這段代碼執(zhí)行完成返回結(jié)果后,才能繼續(xù)往下執(zhí)行,所以,同步調(diào)用是一種阻塞式調(diào)用,主調(diào)方代碼一直阻塞等待直到被調(diào)方返回為止。同步調(diào)用相對比較直觀,也是大部分編程語言直接支持的一種調(diào)用方式。但是,同步調(diào)用在處理比較耗時的情況下會嚴重影響程序性能,影響人機交互的瞬時反應(yīng)。例如,某個程序需要訪問數(shù)據(jù)庫獲取大量數(shù)據(jù),然后根據(jù)這些數(shù)據(jù)進行一系列處理,將處理結(jié)果顯示在程序主窗口。由于數(shù)據(jù)庫訪問和大量數(shù)據(jù)的處理都是耗時的工作,在這個工作完成之前,處理結(jié)果遲遲不能顯示,用戶點擊鼠標也不會立即得到響應(yīng),讓用戶感到整個程序顯得很沉重。面對這樣一些需要比較長時間才能完成的應(yīng)用場景,我們需要采用一種非阻塞式調(diào)用方式,即異步調(diào)用方式。在異步調(diào)用中,主調(diào)方調(diào)用被調(diào)方后,不等待對方返回結(jié)果就繼續(xù)執(zhí)行后續(xù)代碼,被調(diào)方執(zhí)行完畢后,通過某種手段通知調(diào)用方:結(jié)果已經(jīng)出來,請酌情處理。我們可以對上面的例子改用異步調(diào)用將問題輕松化解:把整個耗時的工作放進一個單獨的線程,由主調(diào)方啟動此線程后繼續(xù)執(zhí)行后續(xù)代碼,線程在背后悄悄地處理費時的工作,當工作完成,采用回調(diào)的方式通知主調(diào)方工作完成,主調(diào)方將結(jié)果顯示在主窗口。經(jīng)過這樣的處理,主界面繼續(xù)進行自己的工作而不必死等,就不會造成界面響應(yīng)遲鈍。

我們提供的服務(wù)有:成都網(wǎng)站設(shè)計、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、膠州ssl等。為成百上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學管理、有技術(shù)的膠州網(wǎng)站制作公司

在實現(xiàn)異步調(diào)用機制時,除了線程之外,還要用到回調(diào)?;卣{(diào)是一種雙向調(diào)用,也就是,被調(diào)方在被調(diào)用時也會調(diào)用主調(diào)方的代碼。在異步調(diào)用中,被調(diào)方需要在工作完成時通知主調(diào)方,即調(diào)用主調(diào)方的接口,這一機制通過回調(diào)實現(xiàn)?;卣{(diào)和異步調(diào)用的關(guān)系非常緊密,回調(diào)是異步調(diào)用的基礎(chǔ)[1]。

本文理論聯(lián)系實際,首先闡述如何使用Java實現(xiàn)回調(diào)機制,然后進一步闡述使用Java回調(diào)和線程實現(xiàn)異步調(diào)用,最后,闡述在異步調(diào)用中如何處理超時問題。

1 Java回調(diào)機制的實現(xiàn)方法

實現(xiàn)Java回調(diào),需要做如下三件事情:

(1)定義一個回調(diào)接口CallbackInterface

接口中聲明回調(diào)方法handle,如圖1所示,回調(diào)方法就是一個普通的方法,接收一個消息字符串或者一個封裝了數(shù)據(jù)的事件。

(2)定義一個類實現(xiàn)回調(diào)接口

這個類其實就是消息接收者和處理者,也就是調(diào)用方,回調(diào)方法是消息發(fā)生時實際處理消息的方法,此處簡化為一條打印語句。

(3)定義消息通知者

消息通知者也就是被調(diào)用方必須具備兩種能力,第一,它必須知道誰是消息接收者,第二,當消息發(fā)生時,它能夠回調(diào)這些接收者的回調(diào)方法。為了獲得這兩種能力,消息通知者首先必須提供一個注冊方法register, 通過注冊的方式來注冊多個對此消息或事件感興趣的對象。然后提供一個消息通知方法notifyMessage,在這個方法中調(diào)用所有消息接收者的回調(diào)方法。具體代碼如圖3所示。

比如用一個可變數(shù)組List用于保存消息接收者,注冊的過程實際上是將消息接收者添加到這個數(shù)組,以備在需要通知消息的時候調(diào)用這些消息接收者的回調(diào)方法。

使用Java回調(diào)和線程實現(xiàn)異步調(diào)用

線程是一個獨立的執(zhí)行流,其本質(zhì)是程序中一段并發(fā)執(zhí)行的代碼。在異步調(diào)用機制中引入線程,在線程中完成耗時的工作,其目的是讓調(diào)用方的主線程繼續(xù)執(zhí)行后續(xù)代碼而不需要等待被調(diào)方的結(jié)果返回。由于不需要等待,這樣我們就等于同時做了兩件事情,而這兩件事情分別是在不同的執(zhí)行流中執(zhí)行,主調(diào)者在當前的主線程中執(zhí)行,被調(diào)者在另外一個線程中執(zhí)行,因此提高了程序的效率,避免了界面的響應(yīng)遲鈍。當被調(diào)者執(zhí)行完成后,仍然采用回調(diào)通知主調(diào)者。

例如 LongTimeWorker是一個用于完成耗時工作的線程,同時又是消息通知者。其耗時工作在run方法中完成,另外提供一個注冊方法register, 和一個消息通知方法notifyMessage,在run方法的最后,即耗時工作完成以后,調(diào)用notifyMessage將消息廣播出去。

3 異步調(diào)用中超時問題的處理

異步調(diào)用通常都要加入超時機制,因為我們總是希望在一個指定的時間范圍內(nèi)返回一個結(jié)果,即使沒有得到結(jié)果也該有個超時通知。這時我們需要使用“限時線程回調(diào)方式”,它在原有線程回調(diào)的基礎(chǔ)上加上一個計時器Timer以計算消耗的時間,如果時間期限到了任務(wù)還沒有執(zhí)行完成即中斷線程,并將超時消息廣播出去。LongTimeWorker類需要修改部分的代碼如圖8和圖9所示。

首先LongTimeWorker線程類增加了一個構(gòu)造方法,其參數(shù)是超時時間timeout,構(gòu)造方法的主要任務(wù)是創(chuàng)建一個定時器,每秒鐘計時一次,若超時時間到則終止本線程,并廣播超時消息。LongTimeWorker線程類的第二個改變發(fā)生在其run方法中,線程一啟動立即開始計時,完成工作后停止計時,并廣播消息。

4 結(jié)束語

異步調(diào)用是一種非阻塞式調(diào)用方式,用于在處理比較耗時的任務(wù)時保證程序性能不受到影響。實現(xiàn)異步調(diào)用的關(guān)鍵在于要解決三個技術(shù)難題,它們分別是程序阻塞問題、異步消息的傳遞問題和超時問題。本文介紹的方法采用并發(fā)線程、回調(diào)機制和計時器使上述問題得到了圓滿解決。

java怎么同步發(fā)送及異步發(fā)送短信例子解析

發(fā)送短信的接口

根據(jù)自己的情況選擇服務(wù)商。

開發(fā)文檔

從開發(fā)文檔中我們可以看到. 可以直接使用http請求也可以使用WebService請求發(fā)送短信. 由于DEMO文件夾下的java和jsp文件夾中的代碼都是使用http請求發(fā)送短信. 所以這里就不再細說了, 我們使用WebService的方式演示發(fā)送短信.

生成客戶端代碼

從接口文檔中我們知道它的WebService的WSDL的url為:?那么我們可以執(zhí)行下面的命令生成客戶端代碼:

wsimport -keep

其中wsimport是JDK自帶的工具, -keep url選項是"保留生成的文件". 該命令會在當前目錄下生成sms.cn.ihuyi._106包, 以及眾多的類. 接下來開始編寫我們自己的代碼.

定義接口

為了方便, 這里我們首先定義一個接口:

Sms.java

public?interface?Sms?{

/**

*?向mobile發(fā)送短信,?內(nèi)容為message

*?

*?@param?mobile?手機號

*?@param?message?短信內(nèi)容

*?@return?成功返回-1,?否則返回其他值

*/

int?sendMessage(String?mobile,?String?message);

}

這個接口很簡單, 只有一個方法. 這個方法用來發(fā)送短信.

同步發(fā)送短信

接下來我們首先實現(xiàn)一個同步發(fā)送短信的類:

IhuyiSmsImpl.java

public?class?IhuyiSmsImpl?implements?Sms?{

private?String?account;

private?String?password;

public?void?setAccount(String?account)?{

this.account?=?account;

}

public?void?setPassword(String?password)?{

this.password?=?password;

}

@Override

public?int?sendMessage(String?mobile,?String?message)?{

cn.ihuyi._106.Sms?factory?=?new?cn.ihuyi._106.Sms();

SmsSoap?smsSoap?=?factory.getSmsSoap();

SubmitResult?submit?=?smsSoap.submit(account,?password,?mobile,?message);

int?code?=?submit.getCode();

if(code?==?2){

return?-1;

}

System.out.println("發(fā)送短信失敗,?code:"?+?code);

return?code;

}

}

異步發(fā)送短信

由于發(fā)送短信涉及到網(wǎng)絡(luò)通信, 因此sendMessage方法可能會有一些延遲. 為了改善用戶體驗, 我們可以使用異步發(fā)送短信的方法. 原理很簡單: 如果用戶請求發(fā)送短信, 我們不是直接調(diào)用IhuyiSmsImpl的sendMessage方法, 而是將請求保存起來(生產(chǎn)者), 然后告訴用戶: 短信發(fā)送成功. 之后有若干個消費者取出任務(wù), 調(diào)用sendMessage方法發(fā)送短信.

這里, 我使用線程池完成上面的任務(wù):

AsyncSmsImpl.java

public?class?AsyncSmsImpl?implements?Sms?{

public?Sms?sendSms;

private?ExecutorService?executorService?=?Executors.newFixedThreadPool(3);

public?void?setSendSms(Sms?sendSms)?{

this.sendSms?=?sendSms;

}

@Override

public?int?sendMessage(String?mobile,?String?message)?{

try?{

executorService.submit(()?-?sendSms.sendMessage(mobile,?message));

}

catch(Exception?e)?{

Sysemt.out.println("提交任務(wù)時發(fā)生錯誤"?+?e);

return?0;

}

return?-1;

}

public?void?destroy(){

try{

executorService.shutdown();

}

catch(Exception?e){}

}

}

在第17行, 我們獲得遠程對象的一個代理對象. 之后就可以通過這個代理對象進行發(fā)送短信, 查詢賬戶余額等操作.

第18行, 使用該代理對象的submit方法提交了短信內(nèi)容. 該方法的參數(shù)信息及返回值含義在接口文檔中有詳細的說明.

第19行我們獲得了結(jié)果的狀態(tài)碼. 根據(jù)文檔上的說明, 狀態(tài)碼為2說明提交成功. 簡單起見, 這里我們只關(guān)注提交成功的情況. 需要注意的是, 狀態(tài)碼為2只是說明提交成功. 根據(jù)官網(wǎng)上的"3-5秒內(nèi)響應(yīng)、100%到達", 我們可以推測. 如果提交成功, 那么基本上3-5秒內(nèi),短信就會發(fā)送成功, 根據(jù)用戶的網(wǎng)絡(luò)情況, 可能稍有延遲用戶就可以收到短信.

使用這段代碼發(fā)送短信也很簡單, 直接new一個對象, 設(shè)置好賬號和密碼就可以發(fā)送短信了.

代碼很簡單, 直接將Sms接口的sendMessage(mobile, message)方法作為一個任務(wù)加到線程池的任務(wù)隊列中. 這樣等到有空閑線程時, 就會執(zhí)行sendSms.sendMessage(mobile, message)發(fā)送短信. 這里我們假設(shè)只要保存到線程池就可以成功發(fā)送短信. 因為發(fā)送失敗的情況實際上很罕見.

java 異步編程

用異步輸入輸出流編寫Socket進程通信程序

在Merlin中加入了用于實現(xiàn)異步輸入輸出機制的應(yīng)用程序接口包:java.nio(新的輸入輸出包,定義了很多基本類型緩沖(Buffer)),java.nio.channels(通道及選擇器等,用于異步輸入輸出),java.nio.charset(字符的編碼解碼)。通道(Channel)首先在選擇器(Selector)中注冊自己感興趣的事件,當相應(yīng)的事件發(fā)生時,選擇器便通過選擇鍵(SelectionKey)通知已注冊的通道。然后通道將需要處理的信息,通過緩沖(Buffer)打包,編碼/解碼,完成輸入輸出控制。

通道介紹:

這里主要介紹ServerSocketChannel和 SocketChannel.它們都是可選擇的(selectable)通道,分別可以工作在同步和異步兩種方式下(注意,這里的可選擇不是指可以選擇兩種工作方式,而是指可以有選擇的注冊自己感興趣的事件)??梢杂胏hannel.configureBlocking(Boolean )來設(shè)置其工作方式。與以前版本的API相比較,ServerSocketChannel就相當于ServerSocket(ServerSocketChannel封裝了ServerSocket),而SocketChannel就相當于Socket(SocketChannel封裝了Socket)。當通道工作在同步方式時,編程方法與以前的基本相似,這里主要介紹異步工作方式。

所謂異步輸入輸出機制,是指在進行輸入輸出處理時,不必等到輸入輸出處理完畢才返回。所以異步的同義語是非阻塞(None Blocking)。在服務(wù)器端,ServerSocketChannel通過靜態(tài)函數(shù)open()返回一個實例serverChl。然后該通道調(diào)用serverChl.socket().bind()綁定到服務(wù)器某端口,并調(diào)用register(Selector sel, SelectionKey.OP_ACCEPT)注冊O(shè)P_ACCEPT事件到一個選擇器中(ServerSocketChannel只可以注冊O(shè)P_ACCEPT事件)。當有客戶請求連接時,選擇器就會通知該通道有客戶連接請求,就可以進行相應(yīng)的輸入輸出控制了;在客戶端,clientChl實例注冊自己感興趣的事件后(可以是OP_CONNECT,OP_READ,OP_WRITE的組合),調(diào)用clientChl.connect(InetSocketAddress )連接服務(wù)器然后進行相應(yīng)處理。注意,這里的連接是異步的,即會立即返回而繼續(xù)執(zhí)行后面的代碼。

選擇器和選擇鍵介紹:

選擇器(Selector)的作用是:將通道感興趣的事件放入隊列中,而不是馬上提交給應(yīng)用程序,等已注冊的通道自己來請求處理這些事件。換句話說,就是選擇器將會隨時報告已經(jīng)準備好了的通道,而且是按照先進先出的順序。那么,選擇器是通過什么來報告的呢?選擇鍵(SelectionKey)。選擇鍵的作用就是表明哪個通道已經(jīng)做好了準備,準備干什么。你也許馬上會想到,那一定是已注冊的通道感興趣的事件。不錯,例如對于服務(wù)器端serverChl來說,可以調(diào)用key.isAcceptable()來通知serverChl有客戶端連接請求。相應(yīng)的函數(shù)還有:SelectionKey.isReadable(),SelectionKey.isWritable()。一般的,在一個循環(huán)中輪詢感興趣的事件(具體可參照下面的代碼)。如果選擇器中尚無通道已注冊事件發(fā)生,調(diào)用Selector.select()將阻塞,直到有事件發(fā)生為止。另外,可以調(diào)用selectNow()或者select(long timeout)。前者立即返回,沒有事件時返回0值;后者等待timeout時間后返回。一個選擇器最多可以同時被63個通道一起注冊使用。

應(yīng)用實例:

下面是用異步輸入輸出機制實現(xiàn)的客戶/服務(wù)器實例程序――程序清單1(限于篇幅,只給出了服務(wù)器端實現(xiàn),讀者可以參照著實現(xiàn)客戶端代碼):

程序類圖

public class NBlockingServer {

int port = 8000;

int BUFFERSIZE = 1024;

Selector selector = null;

ServerSocketChannel serverChannel = null;

HashMap clientChannelMap = null;//用來存放每一個客戶連接對應(yīng)的套接字和通道

public NBlockingServer( int port ) {

this.clientChannelMap = new HashMap();

this.port = port;

}

public void initialize() throws IOException {

//初始化,分別實例化一個選擇器,一個服務(wù)器端可選擇通道

this.selector = Selector.open();

this.serverChannel = ServerSocketChannel.open();

this.serverChannel.configureBlocking(false);

InetAddress localhost = InetAddress.getLocalHost();

InetSocketAddress isa = new InetSocketAddress(localhost, this.port );

this.serverChannel.socket().bind(isa);//將該套接字綁定到服務(wù)器某一可用端口

}

//結(jié)束時釋放資源

public void finalize() throws IOException {

this.serverChannel.close();

this.selector.close();

}

//將讀入字節(jié)緩沖的信息解碼

public String decode( ByteBuffer byteBuffer ) throws

CharacterCodingException {

Charset charset = Charset.forName( "ISO-8859-1" );

CharsetDecoder decoder = charset.newDecoder();

CharBuffer charBuffer = decoder.decode( byteBuffer );

String result = charBuffer.toString();

return result;

}

//監(jiān)聽端口,當通道準備好時進行相應(yīng)操作

public void portListening() throws IOException, InterruptedException {

//服務(wù)器端通道注冊O(shè)P_ACCEPT事件

SelectionKey acceptKey =this.serverChannel.register( this.selector,

SelectionKey.OP_ACCEPT );

//當有已注冊的事件發(fā)生時,select()返回值將大于0

while (acceptKey.selector().select() 0 ) {

System.out.println("event happened");

//取得所有已經(jīng)準備好的所有選擇鍵

Set readyKeys = this.selector.selectedKeys();

//使用迭代器對選擇鍵進行輪詢

Iterator i = readyKeys.iterator();

while (i

else if ( key.isReadable() ) {//如果是通道讀準備好事件

System.out.println("Readable");

//取得選擇鍵對應(yīng)的通道和套接字

SelectableChannel nextReady =

(SelectableChannel) key.channel();

Socket socket = (Socket) key.attachment();

//處理該事件,處理方法已封裝在類ClientChInstance中

this.readFromChannel( socket.getChannel(),

(ClientChInstance)

this.clientChannelMap.get( socket ) );

}

else if ( key.isWritable() ) {//如果是通道寫準備好事件

System.out.println("writeable");

//取得套接字后處理,方法同上

Socket socket = (Socket) key.attachment();

SocketChannel channel = (SocketChannel)

socket.getChannel();

this.writeToChannel( channel,"This is from server!");

}

}

}

}

//對通道的寫操作

public void writeToChannel( SocketChannel channel, String message )

throws IOException {

ByteBuffer buf = ByteBuffer.wrap( message.getBytes() );

int nbytes = channel.write( buf );

}

//對通道的讀操作

public void readFromChannel( SocketChannel channel, ClientChInstance clientInstance )

throws IOException, InterruptedException {

ByteBuffer byteBuffer = ByteBuffer.allocate( BUFFERSIZE );

int nbytes = channel.read( byteBuffer );

byteBuffer.flip();

String result = this.decode( byteBuffer );

//當客戶端發(fā)出”@exit”退出命令時,關(guān)閉其通道

if ( result.indexOf( "@exit" ) = 0 ) {

channel.close();

}

else {

clientInstance.append( result.toString() );

//讀入一行完畢,執(zhí)行相應(yīng)操作

if ( result.indexOf( "\n" ) = 0 ){

System.out.println("client input"+result);

clientInstance.execute();

}

}

}

//該類封裝了怎樣對客戶端的通道進行操作,具體實現(xiàn)可以通過重載execute()方法

public class ClientChInstance {

SocketChannel channel;

StringBuffer buffer=new StringBuffer();

public ClientChInstance( SocketChannel channel ) {

this.channel = channel;

}

public void execute() throws IOException {

String message = "This is response after reading from channel!";

writeToChannel( this.channel, message );

buffer = new StringBuffer();

}

//當一行沒有結(jié)束時,將當前字竄置于緩沖尾

public void append( String values ) {

buffer.append( values );

}

}

//主程序

public static void main( String[] args ) {

NBlockingServer nbServer = new NBlockingServer(8000);

try {

nbServer.initialize();

} catch ( Exception e ) {

e.printStackTrace();

System.exit( -1 );

}

try {

nbServer.portListening();

}

catch ( Exception e ) {

e.printStackTrace();

}

}

}

程序清單1

小結(jié):

從以上程序段可以看出,服務(wù)器端沒有引入多余線程就完成了多客戶的客戶/服務(wù)器模式。該程序中使用了回調(diào)模式(CALLBACK)。需要注意的是,請不要將原來的輸入輸出包與新加入的輸入輸出包混用,因為出于一些原因的考慮,這兩個包并不兼容。即使用通道時請使用緩沖完成輸入輸出控制。該程序在Windows2000,J2SE1.4下,用telnet測試成功。

求 JAVA 異步觀察者模式 的源代碼(完整的),不要同步的,好的給加分

package TestObserver;

import java.util.Iterator;

import java.util.Vector;

/**

*

* @author Seastar

*/

interface Observed {

public void addObserver(Observer o);

public void removeObserver(Observer o);

public void update();

}

interface Observer {

public void takeAction();

}

class Invoker {

private Observer o;

Handler handler;

public Invoker(Observer o) {

new Handler();

this.o = o;

}

private class Handler extends Thread {

public Handler() {

handler = this;

}

@Override

public void run() {

o.takeAction();

}

}

public boolean TestSameObserver(Observer o) {

return o == this.o;

}

public void invoke() {

handler.start();

}

}

class ObservedObject implements Observed {

private VectorInvoker observerList = new VectorInvoker();

public void addObserver(Observer o) {

observerList.add(new Invoker(o));

}

public void removeObserver(Observer o) {

IteratorInvoker it = observerList.iterator();

while (it.hasNext()) {

Invoker i = it.next();

if (i.TestSameObserver(o)) {

observerList.remove(i);

break;

}

}

}

public void update() {

for (Invoker i : observerList) {

i.invoke();

}

}

}

class ObserverA implements Observer {

public void takeAction() {

System.out.println("I am Observer A ,state changed ,so i have to do something");

}

}

class ObserverB implements Observer {

public void takeAction() {

System.out.println("I am Observer B ,i was told to do something");

}

}

class ObserverC implements Observer {

public void takeAction() {

System.out.println("I am Observer C ,I just look ,and do nothing");

}

}

public class Main {

/**

* @param args the command line arguments

*/

public static void main(String[] args) {

ObserverA a = new ObserverA();

ObserverB b = new ObserverB();

ObserverC c = new ObserverC();

ObservedObject oo = new ObservedObject();

oo.addObserver(a);

oo.addObserver(b);

oo.addObserver(c);

for (int i = 0; i 5; ++i) {

oo.addObserver(new Observer() {

public void takeAction() {

System.out.println("我是山寨觀察者"+",誰敢攔我");

}

});

}

//sometime oo changed ,so it calls update and informs all observer

oo.update();

}

}

觀察者模式的精髓在于注冊一個觀察者觀測可能隨時變化的對象,對象變化時就會自動通知觀察者,

這樣在被觀測對象影響范圍廣,可能引起多個類的行為改變時很好用,因為無需修改被觀測對象的代碼就可以增加被觀測對象影響的類,這樣的設(shè)計模式使得代碼易于管理和維護,并且減少了出錯幾率

至于異步機制實際是個噱頭,可以有觀測對象來實現(xiàn)異步,也可以有觀察者自身實現(xiàn),這個程序?qū)嶋H是觀測對象實現(xiàn)了異步機制,方法是在觀察者類外包裝了一層invoker類

java隊列實現(xiàn)異步執(zhí)行

在整個思路上要調(diào)整一下

1、會有很多線程給一個隊列上添加任務(wù)

2、有一個或者多個線程逐個執(zhí)行隊列的任務(wù)

考慮一下幾點:

1、沒有任務(wù)時,隊列執(zhí)行線程處于等待狀態(tài)

2、添加任務(wù)時,激活隊列執(zhí)行線程,全部run起來,首先搶到任務(wù)的執(zhí)行,其他全部wait

給個小例子吧

package?org;

import?java.util.LinkedList;

import?java.util.List;

public?class?Queues?{

public?static?ListTask?queue?=?new?LinkedListTask();

/**

?*?假如?參數(shù)o?為任務(wù)

?*?@param?o

?*/

public?static?void?add?(Task?t){

synchronized?(Queues.queue)?{

Queues.queue.add(t);?//添加任務(wù)

Queues.queue.notifyAll();//激活該隊列對應(yīng)的執(zhí)行線程,全部Run起來

}

}

static?class?Task{

public?void?test(){

System.out.println("我被執(zhí)行了");

}

}

}

package?org;

import?java.util.List;

public?class?Exec?implements?Runnable{

@Override

public?void?run()?{

while(true){

synchronized?(Queues.queue)?{

while(Queues.queue.isEmpty()){?//

try?{

Queues.queue.wait();?//隊列為空時,使線程處于等待狀態(tài)

}?catch?(InterruptedException?e)?{

e.printStackTrace();

}

System.out.println("wait...");

}

Queues.Task?t=?Queues.queue.remove(0);?//得到第一個

t.test();?//執(zhí)行該任務(wù)

System.out.println("end");

}

}

}

public?static?void?main(String[]?args)?{

Exec?e?=?new?Exec();

for?(int?i?=?0;?i??2;?i++)?{

new?Thread(e).start();?//開始執(zhí)行時,隊列為空,處于等待狀態(tài)

}

//上面開啟兩個線程執(zhí)行隊列中的任務(wù),那就是先到先得了

//添加一個任務(wù)測試

Queues.Task?t?=new?Queues.Task();

Queues.add(t);?//執(zhí)行該方法,激活所有對應(yīng)隊列,那兩個線程就會開始執(zhí)行啦

}

}

上面的就是很簡單的例子了

java 異步調(diào)用方法

1. 使用wait和notify方法

這個方法其實是利用了鎖機制,直接貼代碼:

public class Demo1 extends BaseDemo{ private final Object lock = new Object(); @Override public void callback(long response) { System.out.println("得到結(jié)果"); System.out.println(response); System.out.println("調(diào)用結(jié)束"); synchronized (lock) { lock.notifyAll(); } } public static void main(String[] args) { Demo1 demo1 = new Demo1(); demo1.call(); synchronized (demo1.lock){ try { demo1.lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("主線程內(nèi)容"); } }

可以看到在發(fā)起調(diào)用后,主線程利用wait進行阻塞,等待回調(diào)中調(diào)用notify或者notifyAll方法來進行喚醒。注意,和大家認知的一樣,這里wait和notify都是需要先獲得對象的鎖的。在主線程中最后我們打印了一個內(nèi)容,這也是用來驗證實驗結(jié)果的,如果沒有wait和notify,主線程內(nèi)容會緊隨調(diào)用內(nèi)容立刻打印;而像我們上面的代碼,主線程內(nèi)容會一直等待回調(diào)函數(shù)調(diào)用結(jié)束才會進行打印。

沒有使用同步操作的情況下,打印結(jié)果:發(fā)起調(diào)用 調(diào)用返回 主線程內(nèi)容 得到結(jié)果 1 調(diào)用結(jié)束

而使用了同步操作后:

發(fā)起調(diào)用 調(diào)用返回 得到結(jié)果 9 調(diào)用結(jié)束 主線程內(nèi)容2. 使用條件鎖

和方法一的原理類似:

public class Demo2 extends BaseDemo { private final Lock lock = new ReentrantLock(); private final Condition con = lock.newCondition(); @Override public void callback(long response) { System.out.println("得到結(jié)果"); System.out.println(response); System.out.println("調(diào)用結(jié)束"); lock.lock(); try { con.signal(); }finally { lock.unlock(); } } public static void main(String[] args) { Demo2 demo2 = new Demo2(); demo2.call(); demo2.lock.lock(); try { demo2.con.await(); } catch (InterruptedException e) { e.printStackTrace(); }finally { demo2.lock.unlock(); } System.out.println("主線程內(nèi)容"); } }

基本上和方法一沒什么區(qū)別,只是這里使用了條件鎖,兩者的鎖機制有所不同。


網(wǎng)頁標題:java異步接口代碼 java異步代碼塊
當前URL:http://weahome.cn/article/doosjss.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部