android多线程网络通信


动机:前几天去面试,重点问了一些关于多线程网络通信的问题。这块也的确很重要。特总结一下自己对多线程这块的理解和实现方式。

 

带着一些问题。。。。。。。

怎么进行网络通信?

网络通信需要注意哪些?

网络连接池怎么来进行实现?

 

1.怎么进行网络通信?

         网络接口+多线程

2. 网络通信需要注意哪些?

         稳定+健壮+效率

3. 网络连接池的实现

         有自定义实现

         也可以使用第三方框架

 

无论是使用自定义实现还是使用第三方框架都会遇到这些问题。就是网络连接池的基本框架是什么样子的。基本原理是这样的,有一个线程的列表,还有一个报文的列表。报文的列表分为有界的和无界的。这个需要根据需求来定了。 我遇到最多的就是无界的了。 当添加一个报文任务的时候,取得一个空闲的线程来做,当再增加一个报文任务的时候,再取得一条空闲的线程来做。当线程都在忙的时候。在增加报文任务的时候,把这些报文任务添加到报文列表中,当线程有空闲的时候,再来取报文列表中的任务来做。

 

自定义实现(无界的报文列表):

  1. notify,wait 方法是用的时候,包含这个方法的方法,需要加上同步锁。

例如:

   

 /**

     * 等待操作

     */

    private synchronized void httpThreadWait()

    {

            try

            {

                if(!isRunning()){

                    wait();

                }

            }

            catch (InterruptedException e)

            {

                System.out.println(e.toString());

            }

    }

 

2.同步锁的三种方式

         对类进行加锁

例如:

    /**

     * 发送数据包

     * @param httpPacket 数据包

     */

    private synchronized static void sendHttpPacket(HttpPacket httpPacket){

        //增加数据包到报文列表

        HttpThreadPool httpThreadPool = HttpThreadPool.instance();

        httpThreadPool.addHttpPacket(httpPacket);

        //如果有空闲的线程就取得,然后去处理报文

        HttpThread httpThread = httpThreadPool.getFreeHttpThread();

        if(null != httpThread){

            httpThread.setRunning(true);

        }

}

  

对象锁:

一种是全局对象锁

例如:

    /**

     * 得到最前面的报文

     * @return HttpPacket 报文

     */

    public synchronized HttpPacket getFirstHttpPacket(){

        if(isHaveHttpPacket()){

            HttpPacket temp = httpPackets.get(0);

            httpPackets.remove(0);

            return temp;

        }

        else{

            return null;

        }

    }

  

一种是局部函数对象锁

例如:

    /**

     * 按键事件同步锁

     */

    private byte[] keyLock = new byte[0];

    /**

     * 按键按下事件

     *

     * @param keyCode

     *            键值

     * @param event

     *            事件

     * @return 是否响应

     */

    public boolean onKeyDown(int keyCode, KeyEvent event)

    {

        synchronized (keyLock)

        {

            if (keyEventList.size() > MAX_EVENT)

            {

                keyEventList.remove(0);

            }

            keyEventList.add(new KeyAction(KeyAction.KEY_DOWN, keyCode));

        }

        return true;

    }

 

 

自定义框架代码:

 

View Code
 1 /*
 2  * 文 件 名:  HttpPacket.java
 3  * 描    述:  <描述>
 4  * 修 改 人:  吴佳峻
 5  * 修改时间:  2012-4-23
 6  * 跟踪单号:  <跟踪单号>
 7  * 修改单号:  <修改单号>
 8  * 修改内容:  <修改内容>
 9  */
10 package thread.pool;
11 /**
12  * http报文
13  * <一句话功能简述>
14  * <功能详细描述>
15  * 
16  * @author  吴佳峻
17  * @version  2012-4-23
18  * @see  [相关类/方法]
19  */
20 public class HttpPacket
21 {
22     private int id;
23     private String url;
24     private IHttpHandler handler;
25     private boolean isCancel;
26     
27 
28     public boolean isCancel()
29     {
30         return isCancel;
31     }
32     public void setCancel(boolean isCancel)
33     {
34         this.isCancel = isCancel;
35     }
36     public IHttpHandler getHandler()
37     {
38         return handler;
39     }
40     public void setHandler(IHttpHandler handler)
41     {
42         this.handler = handler;
43     }
44     public int getId()
45     {
46         return id;
47     }
48     public void setId(int id)
49     {
50         this.id = id;
51     }
52     public String getUrl()
53     {
54         return url;
55     }
56     public void setUrl(String url)
57     {
58         this.url = url;
59     }
60     
61 }
View Code
 1 /*
 2  * 文 件 名:  IHttpHandler.java
 3  * 描    述:  <描述>
 4  * 修 改 人:  吴佳峻
 5  * 修改时间:  2012-4-23
 6  * 跟踪单号:  <跟踪单号>
 7  * 修改单号:  <修改单号>
 8  * 修改内容:  <修改内容>
 9  */
10 package thread.pool;
11 
12 
13 public interface IHttpHandler
14 {
15     public static final int SERVER_ERROR = 0;
16     public static final int USER_CANCEL = 1;
17     public static final int CONNECT_ERROR = 2;
18     public static final int OK = 3;
19     
20     void response(int result,Object data,int id,String desc);
21 }
View Code
 1 /*
 2  * 文 件 名:  ProductHandler.java
 3  * 描    述:  <描述>
 4  * 修 改 人:  吴佳峻
 5  * 修改时间:  2012-4-25
 6  * 跟踪单号:  <跟踪单号>
 7  * 修改单号:  <修改单号>
 8  * 修改内容:  <修改内容>
 9  */
10 package thread.pool;
11 
12 public class ProductHandler implements IHttpHandler
13 {
14     
15     @Override
16     public void response(int result, Object data, int id, String desc)
17     {
18         System.out.println("result:"+result+" data:"+data.toString()+" id:"+id+" desc:"+desc);
19     }
20     
21 }
View Code
  1 /*
  2  * 文 件 名:  HttpTask.java
  3  * 描    述:  <描述>
  4  * 修 改 人:  吴佳峻
  5  * 修改时间:  2012-4-23
  6  * 跟踪单号:  <跟踪单号>
  7  * 修改单号:  <修改单号>
  8  * 修改内容:  <修改内容>
  9  */
 10 package thread.pool;
 11 
 12 import java.io.ByteArrayOutputStream;
 13 import java.io.IOException;
 14 import java.io.InputStream;
 15 import java.net.HttpURLConnection;
 16 import java.net.URL;
 17 
 18 
 19 
 20 /**
 21  * http任务
 22  * <一句话功能简述>
 23  * <功能详细描述>
 24  * 
 25  * @author  吴佳峻
 26  * @version  2012-4-23
 27  * @see  [相关类/方法]
 28  */
 29 public class HttpThread implements Runnable
 30 {
 31 
 32     private boolean isRunning;
 33     
 34     private HttpPacket httpPacket;
 35     
 36 //    private IHttpHandler handler;
 37     
 38     private HttpURLConnection httpUrlConn;
 39     
 40     public boolean isRunning()
 41     {
 42         return isRunning;
 43     }
 44 
 45     /**
 46      * 设置是否运行
 47      * @param isRunning 是否运行
 48      */
 49     public synchronized void setRunning(boolean isRunning){
 50         this.isRunning = isRunning;
 51         if(isRunning){
 52             notify();
 53         }
 54     }
 55     
 56     @Override
 57     public void run()
 58     {
 59         while(true){
 60             try
 61             {
 62                 //等待
 63                 httpThreadWait();
 64                 
 65                 boolean isHavePacket = HttpThreadPool.instance().isHaveHttpPacket();
 66                 if(isHavePacket){
 67                     //取得连接
 68                     httpPacket = HttpThreadPool.instance().getFirstHttpPacket();
 69                     httpUrlConn = httpConnect(httpPacket);
 70                     
 71                     // 处理服务器返回数据
 72                     dealResponse(httpUrlConn,httpPacket.getHandler());
 73                 }
 74 
 75                 
 76             }
 77             catch (IOException e)
 78             {
 79                 e.printStackTrace();
 80             }
 81             finally
 82             {
 83                 if (null != httpUrlConn)
 84                 {
 85                     //httpConn.close();
 86                     httpUrlConn.disconnect();
 87                     httpUrlConn = null;
 88                 }
 89                 // 结束操作
 90                 endRun();
 91             }
 92         }
 93     }
 94     
 95 
 96     
 97     /**
 98      * 结束操作
 99      */
100     private void endRun()
101     {
102         setRunning(false);
103         if(HttpThreadPool.instance().isHaveHttpPacket()){
104             setRunning(true);
105         }
106     }
107 
108     /**
109      * 等待操作
110      */
111     private synchronized void httpThreadWait()
112     {
113             try
114             {
115                 if(!isRunning()){
116                     wait();
117                 }
118             }
119             catch (InterruptedException e)
120             {
121                 System.out.println(e.toString());
122             }
123     }
124 
125     /*
126      * 建立HTTP连接
127      * 
128      * @param request
129      *            请求对象
130      * @return HttpURLConnection http连接对象
131      */
132     private HttpURLConnection httpConnect(HttpPacket httpPacket) throws IOException
133     {
134         HttpURLConnection conn = null;
135                 URL url = new URL(httpPacket.getUrl());
136             conn = (HttpURLConnection) url.openConnection();
137             conn.setRequestProperty("Accept", "*/*");
138             conn.setRequestProperty("User-Agent", "android");
139             conn.setRequestMethod("GET");
140         return conn;
141     }
142     
143     /*
144      * 处理服务器响应 向回调Handler传递数据
145      * 
146      * @param setHttpConns HTTP连接
147      * @param handler 回调Handler
148      * @return
149      * @throws IOException 流异常
150      * 
151      * @return boolean 服务器是否成功响应
152      */
153     private void dealResponse(HttpURLConnection setHttpConn,IHttpHandler handler)
154             throws IOException
155     {
156         
157         
158         // 获取服务器响应数据
159         byte[] data = getResponseData(setHttpConn);
160         if (data == null)
161         {
162             System.out.println("err,response inputstream data is null!");
163             if (!httpPacket.isCancel())
164             {
165                 handler.response(IHttpHandler.SERVER_ERROR, null, httpPacket.getId(), "无响应数据");
166             }
167             else
168             {
169                 handler.response(IHttpHandler.USER_CANCEL, null, httpPacket.getId(), "无响应数据");
170             }
171         }
172         else
173         {
174             if (!httpPacket.isCancel())
175             {
176                 
177                 String getData = new String(data, "UTF-8");
178                 
179 //                System.out.println("receive data:" + getData);
180                 if (getData == null || getData.equals(""))
181                 {
182                     System.out.println("receive data string empty!!!!!!");
183                     handler.response(IHttpHandler.SERVER_ERROR, null, httpPacket.getId(), "无响应数据");
184                     return;
185                 }
186                 String metaBean = null;
187                 try
188                 {
189                     metaBean = "abasdkjfasjdf;laksjd;flkajs;dfj;asdjf;";
190                 }
191                 catch (Exception e)
192                 {
193                     System.out.println("meta parse error!");
194                     handler.response(IHttpHandler.CONNECT_ERROR, null, httpPacket.getId(), null);
195                     return;
196                 }
197                 handler.response(IHttpHandler.OK, metaBean, httpPacket.getId(), "成功");
198             }
199         }
200         
201         //closeInputStream(is);
202         //is = null;
203     }
204     
205     /*
206      * 获取服务器响应数据 
207      * 
208      * @param setHttpConn 连接对象
209      * @param is 输入流
210      * @return 响应的byte[]
211      * @throws IOException 异常
212      */
213     private byte[] getResponseData(HttpURLConnection setHttpConn)
214     {
215         InputStream is = null;
216         ByteArrayOutputStream baos = null;
217         try
218         {
219             //is = setHttpConn.openInputStream();
220             is = setHttpConn.getInputStream();
221             if (is == null)
222             {
223                 return null;
224             }
225             baos = new ByteArrayOutputStream();
226             boolean stopReading = false;
227             int c = 0;
228             while ((c = is.read()) != -1)
229             {
230                 if (httpPacket.isCancel())
231                 {
232                     stopReading = true;
233                     break;
234                 }
235                 baos.write(c);
236             }
237             if (stopReading)
238             {
239                 //closeOutputStream(baos);
240                 
241                 return null;
242             }
243             byte[] data = baos.toByteArray();
244             //closeOutputStream(baos);
245             return data;
246         }
247         catch (IOException e)
248         {
249             System.out.println(e.toString());
250         }
251         finally
252         {
253             try
254             {
255                 if (baos != null)
256                 {
257                     baos.close();
258                     baos = null;
259                 }
260                 
261                 if (is != null)
262                 {
263                     is.close();
264                     is = null;
265                 }
266             }
267             catch (IOException e)
268             {
269                 System.out.println(e.toString());
270             }
271         }
272         return null;
273     }
274 }
View Code
  1 /*
  2  * 文 件 名:  HttpThreadPool.java
  3  * 描    述:  <描述>
  4  * 修 改 人:  吴佳峻
  5  * 修改时间:  2012-4-23
  6  * 跟踪单号:  <跟踪单号>
  7  * 修改单号:  <修改单号>
  8  * 修改内容:  <修改内容>
  9  */
 10 package thread.pool;
 11 
 12 import java.util.ArrayList;
 13 
 14 /**
 15  * http连接池
 16  * <一句话功能简述>
 17  * <功能详细描述>
 18  * 
 19  * @author  吴佳峻
 20  * @version  2012-4-23
 21  * @see  [相关类/方法]
 22  */
 23 public class HttpThreadPool
 24 {
 25     //最小的线程数
 26     public static final int COREPOOLSIZE = 2;
 27     
 28     //最大的线程数
 29     public static final int MAXPOOLSIZE = 5;
 30     
 31     private static HttpThreadPool httpThreadPool;
 32     
 33     //报文列表
 34     private ArrayList<HttpPacket> httpPackets = new ArrayList<HttpPacket>();
 35     
 36     //线程列表
 37     private ArrayList<HttpThread> httpThreads = new ArrayList<HttpThread>();
 38     
 39     private HttpThreadPool(){
 40         for(int i=0;i<COREPOOLSIZE;i++){
 41             HttpThread ht = new HttpThread();
 42             Thread t = new Thread(ht);
 43             t.start();
 44             httpThreads.add(ht);
 45         }
 46     }
 47     
 48     /**
 49      * 取得一个实例
 50      * 单例,同步锁
 51      * @return HttpThreadPool 线程池
 52      */
 53     public synchronized static HttpThreadPool instance(){
 54         if(null == httpThreadPool){
 55             httpThreadPool = new HttpThreadPool();
 56         }
 57         return httpThreadPool;
 58     }
 59     
 60     /**
 61      * 增加一个报文
 62      * @param e 报文
 63      */
 64     public synchronized void addHttpPacket(HttpPacket e){
 65         httpPackets.add(e);
 66     }
 67     
 68 //    /**
 69 //     * 删除排在最前面的报文
 70 //     */
 71 //    public synchronized void removeFirstHttpPacket(){
 72 //        if(httpPackets.size()!=0){
 73 //            httpPackets.remove(0);
 74 //        }
 75 //    }
 76     
 77     /**
 78      * 得到最前面的报文
 79      * @return HttpPacket 报文
 80      */
 81     public synchronized HttpPacket getFirstHttpPacket(){
 82         if(isHaveHttpPacket()){
 83             HttpPacket temp = httpPackets.get(0);
 84             httpPackets.remove(0);
 85             return temp;
 86         }
 87         else{
 88             return null;
 89         }
 90     }
 91     /**
 92      * 
 93      * 列表中是否有报文
 94      * @return boolean 列表中是否有报文
 95      */
 96     public synchronized boolean isHaveHttpPacket(){
 97         if(httpPackets.size()!=0){
 98             return true;
 99         }
100         return false;
101     }
102     
103     /**
104      * 取得空闲的线程
105      * 如果没有到达最大值就生成一个返回,如果超过的话,就返回空
106      * @return HttpThread [返回类型说明]
107      */
108     public synchronized HttpThread getFreeHttpThread(){
109         //已经存在的列表中是否有空闲的线程
110         for(int i=0;i<httpThreads.size();i++){
111             HttpThread t = httpThreads.get(i);
112             if(!t.isRunning()){
113                 return t;
114             }
115         }
116         //如果没有的话,当线程数小于最大线程数的时候,创建一条线程
117         if(httpThreads.size()<MAXPOOLSIZE){
118             HttpThread t = new HttpThread();
119             httpThreads.add(t);
120             return t;
121         }
122         //大于最大线程数的时候,返回空
123         return null;
124     }
125     
126     
127 }
View Code
 1 /*
 2  * 文 件 名:  HttpTest.java
 3  * 描    述:  <描述>
 4  * 修 改 人:  吴佳峻
 5  * 修改时间:  2012-4-24
 6  * 跟踪单号:  <跟踪单号>
 7  * 修改单号:  <修改单号>
 8  * 修改内容:  <修改内容>
 9  */
10 package thread.pool;
11 
12 public class HttpTest
13 {
14     
15     /** <一句话功能简述>
16      * <功能详细描述>
17      * @param args [参数说明]
18      * 
19      * @return void [返回类型说明]
20      * @exception throws [违例类型] [违例说明]
21      * @see [类、类#方法、类#成员]
22      */
23     public static void main(String[] args)
24     {
25         for(int i=0;i<100;i++){
26             sendOnePacket(i);
27         }
28     }
29 
30     private static void sendOnePacket(int i)
31     {
32         HttpPacket p1 = new HttpPacket();
33         p1.setId(i);
34         p1.setUrl("http://www.baidu.com/");
35         p1.setHandler(new ProductHandler());
36         sendHttpPacket(p1);
37     }
38     
39     
40     /**
41      * 发送数据包
42      * @param httpPacket 数据包
43      */
44     private synchronized static void sendHttpPacket(HttpPacket httpPacket){
45         //增加数据包到报文列表
46         HttpThreadPool httpThreadPool = HttpThreadPool.instance();
47         httpThreadPool.addHttpPacket(httpPacket);
48         //如果有空闲的线程就取得,然后去处理报文
49         HttpThread httpThread = httpThreadPool.getFreeHttpThread();
50         if(null != httpThread){
51             httpThread.setRunning(true);
52         }
53     }
54 }

 

 

使用第三方框架实现(无界的报文列表):

 //待续。。。。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM