关闭

Android 线程的结束,挂起和恢复

标签: 线程等待
1016人阅读 评论(0) 收藏 举报
分类:

转自http://blog.sina.com.cn/s/blog_4c0706560101175r.html

Android线程类也提供了一些公共方法去挂起和恢复线程:

final void resume()                                       
//This method is deprecated. Used with deprecated method suspend
final void suspend()
//This method is deprecated. May cause deadlocks

同样不幸的是,通过说明我们可以看到,这些方法Android也是不推荐使用的,经过笔者试验,这些方法也没有效果
Android的类基本都是继承于Object类。此类可以说是Android类的祖先了。如果把Android类比喻为一个生物界,则Object类就是当初生命诞生时候的那个单细胞。
       我们可以发现Object类提供了几个方法 :
final void notify()
Causes a thread which is waiting on this object's monitor (by means of calling one of the wait() methods) to be woken
final void notifyAll()
Causes all threads which are waiting on this object's monitor (by means of calling one of the wait() methods) to be woken
final void wait()
Causes the calling thread to wait until another thread calls the notify() or notifyAll() method of this object

通过说明我们可以知道,wait方法可以让正在调用的线程处于等待状态,直到其他线程调用了该对象的notify 或者notifyAll,而notify 和notifyAll方法则是用于唤醒处于等待中的线程。
       同样,线程类也是继承于Object类,但是线程类是一个比较特殊的类,有自己独立的栈机制来处理其方法,参数和局部变量。通过实验,笔者发现,虽然线程类继承于Object类,但是却不能通过wait和notify方法挂起唤醒线程。而要实现上述动作,必须去间接地实现,即在自定义线程类中创建一个Object对象,然后通过对该Object的相关操作实现线程的挂起和唤醒。方法如下:
1.    在自定义线程类的实例化过程中创建一个Object对象。
2.    定义一个变量来记录线程的状态是否挂起,初始化为假。
3.    在线程类中的run函数中的线程执行部分找入锲点来执行下面动作:如果当前状态变量为假(表示线程挂起),则通过1中Object对象的wait方法挂起当前线程,即线程暂停在锲点位置,如果被唤起,则将从锲点后继续执行。
4.    定义一个方法来修改线程状态变量为真,从而达到挂起线程的目的。
5.    定义一个方法去唤醒线程。判断如果线程状态变量为真,则修改其为假,然后调用1中Object对象的notifyAll方法唤醒对象。(notify方法也可以,但是如果自定义线程较多时容易造成死锁)。
综上,当自定义线程运行后我们可以通过4中的方法挂起线程,通过5中的方法唤醒线程。
class SearchThread extends Thread
   {
      private Object mPauseLock ;
      private boolean mPauseFlag ;   
     
      public SearchThread()
      {
         
          mPauseLock = new Object() ;
          mPauseFlag = false ;
      }
     
      public void onPause()
      {
          synchronized (mPauseLock) {
             mPauseFlag = true;
             }
      }
     
      public void onResume()
      {
          synchronized (mPauseLock) {
             mPauseFlag = false ;
             mPauseLock.notifyAll() ;
             }
      }
            
      private void pauseThread()
      {
          synchronized (mPauseLock) {
             if(mPauseFlag)
             {
                try{
                   mPauseLock.wait() ;
                }catch(Exception e){
                   Log.v("thread", "fails") ;
                }
             }
             }
      }    
 
@Override
      public void run()
    {
       ……
       //---线程执行部分,仅仅举例为了说明-----
         for(int i = 0; i < 100; i++)
      {
          pauseThread() ;
          ……
          for(int j = 0; j < 100; j++)
          {
               pauseThread() ;
               ……
          }
}
       //-----end----------
       ……
      }
}


根据上面说的这种方法,然后就翻了下XUtis图片缓存的源码,它图片的缓存采用Lru(最近使用算法),下面是其部分代码

public class BitmapCache {

    private final int DISK_CACHE_INDEX = 0;

    private LruDiskCache mDiskLruCache;
    private LruMemoryCache<MemoryCacheKey, Bitmap> mMemoryCache;

    private final Object mDiskCacheLock = new Object();
    private boolean isDiskCacheReadied = false;

    private BitmapGlobalConfig globalConfig;

    /**
     * Creating a new ImageCache object using the specified parameters.
     *
     * @param globalConfig The cache parameters to use to initialize the cache
     */
    public BitmapCache(BitmapGlobalConfig globalConfig) {
        if (globalConfig == null) throw new IllegalArgumentException("globalConfig may not be null");
        this.globalConfig = globalConfig;
    }


    /**
     * Initialize the memory cache
     */
    public void initMemoryCache() {
        if (!globalConfig.isMemoryCacheEnabled()) return;

        // Set up memory cache
        if (mMemoryCache != null) {
            try {
                clearMemoryCache();
            } catch (Throwable e) {
            }
        }
        mMemoryCache = new LruMemoryCache<MemoryCacheKey, Bitmap>(globalConfig.getMemoryCacheSize()) {
            /**
             * Measure item size in bytes rather than units which is more practical
             * for a bitmap cache
             */
            @Override
            protected int sizeOf(MemoryCacheKey key, Bitmap bitmap) {
                if (bitmap == null) return 0;
                return bitmap.getRowBytes() * bitmap.getHeight();
            }
        };
    }

    /**
     * Initializes the disk cache.  Note that this includes disk access so this should not be
     * executed on the main/UI thread. By default an ImageCache does not initialize the disk
     * cache when it is created, instead you should call initDiskCache() to initialize it on a
     * background thread.
     */
    public void initDiskCache() {
        if (!globalConfig.isDiskCacheEnabled()) return;

        // Set up disk cache
        synchronized (mDiskCacheLock) {
            if (mDiskLruCache == null || mDiskLruCache.isClosed()) {
                File diskCacheDir = new File(globalConfig.getDiskCachePath());
                if (!diskCacheDir.exists()) {
                    diskCacheDir.mkdirs();
                }
                long availableSpace = BitmapCommonUtils.getAvailableSpace(diskCacheDir);
                long diskCacheSize = globalConfig.getDiskCacheSize();
                diskCacheSize = availableSpace > diskCacheSize ? diskCacheSize : availableSpace;
                try {
                    mDiskLruCache = LruDiskCache.open(diskCacheDir, 1, 1, diskCacheSize);
                    mDiskLruCache.setDiskCacheFileNameGenerator(globalConfig.getDiskCacheFileNameGenerator());
                } catch (Throwable e) {
                    mDiskLruCache = null;
                    LogUtils.e(e.getMessage(), e);
                }
            }
            isDiskCacheReadied = true;
            mDiskCacheLock.notifyAll();
        }
    }

 
    public Bitmap downloadBitmap(String uri, BitmapDisplayConfig config, final BitmapUtils.BitmapLoadTask<?> task) {

        BitmapMeta bitmapMeta = new BitmapMeta();

        OutputStream outputStream = null;
        LruDiskCache.Snapshot snapshot = null;

        try {

            Bitmap bitmap = null;
            // try download to disk
            if (globalConfig.isDiskCacheEnabled()) {
                synchronized (mDiskCacheLock) {
                    // Wait for disk cache to initialize
                    while (!isDiskCacheReadied) {//为false则等待
                        try {
							//使线程处于等待状态
                            mDiskCacheLock.wait();
                        } catch (Throwable e) {
                        }
                    }

                    if (mDiskLruCache != null) {
                        try {
                            snapshot = mDiskLruCache.get(uri);
                            if (snapshot == null) {
                                LruDiskCache.Editor editor = mDiskLruCache.edit(uri);
                                if (editor != null) {
                                    outputStream = editor.newOutputStream(DISK_CACHE_INDEX);
                                    bitmapMeta.expiryTimestamp = globalConfig.getDownloader().downloadToStream(uri, outputStream, task);
                                    if (bitmapMeta.expiryTimestamp < 0) {
                                        editor.abort();
                                        return null;
                                    } else {
                                        editor.setEntryExpiryTimestamp(bitmapMeta.expiryTimestamp);
                                        editor.commit();
                                    }
                                    snapshot = mDiskLruCache.get(uri);
                                }
                            }
                            if (snapshot != null) {
                                bitmapMeta.inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
                                bitmap = decodeBitmapMeta(bitmapMeta, config);
                                if (bitmap == null) {
                                    bitmapMeta.inputStream = null;
                                    mDiskLruCache.remove(uri);
                                }
                            }
                        } catch (Throwable e) {
                            LogUtils.e(e.getMessage(), e);
                        }
                    }
                }
            }

            // try download to memory stream
            if (bitmap == null) {
                outputStream = new ByteArrayOutputStream();
                bitmapMeta.expiryTimestamp = globalConfig.getDownloader().downloadToStream(uri, outputStream, task);
                if (bitmapMeta.expiryTimestamp < 0) {
                    return null;
                } else {
                    bitmapMeta.data = ((ByteArrayOutputStream) outputStream).toByteArray();
                    bitmap = decodeBitmapMeta(bitmapMeta, config);
                }
            }

            if (bitmap != null) {
                bitmap = rotateBitmapIfNeeded(uri, config, bitmap);
                addBitmapToMemoryCache(uri, config, bitmap, bitmapMeta.expiryTimestamp);
            }
            return bitmap;
        } catch (Throwable e) {
            LogUtils.e(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(outputStream);
            IOUtils.closeQuietly(snapshot);
        }

        return null;
    }
 
    /**
     * Get the bitmap from disk cache.
     *
     * @param uri
     * @param config
     * @return
     */
    public Bitmap getBitmapFromDiskCache(String uri, BitmapDisplayConfig config) {
        if (uri == null || !globalConfig.isDiskCacheEnabled()) return null;
        synchronized (mDiskCacheLock) {
            while (!isDiskCacheReadied) {
                try {
                    mDiskCacheLock.wait();
                } catch (Throwable e) {
                }
            }
            if (mDiskLruCache != null) {
                LruDiskCache.Snapshot snapshot = null;
                try {
                    snapshot = mDiskLruCache.get(uri);
                    if (snapshot != null) {
                        Bitmap bitmap = null;
                        if (config == null || config.isShowOriginal()) {
                            bitmap = BitmapDecoder.decodeFileDescriptor(
                                    snapshot.getInputStream(DISK_CACHE_INDEX).getFD());
                        } else {
                            bitmap = BitmapDecoder.decodeSampledBitmapFromDescriptor(
                                    snapshot.getInputStream(DISK_CACHE_INDEX).getFD(),
                                    config.getBitmapMaxSize(),
                                    config.getBitmapConfig());
                        }

                        bitmap = rotateBitmapIfNeeded(uri, config, bitmap);
                        addBitmapToMemoryCache(uri, config, bitmap, mDiskLruCache.getExpiryTimestamp(uri));
                        return bitmap;
                    }
                } catch (Throwable e) {
                    LogUtils.e(e.getMessage(), e);
                } finally {
                    IOUtils.closeQuietly(snapshot);
                }
            }
            return null;
        }
    }
 

    public void clearDiskCache() {
        synchronized (mDiskCacheLock) {
            if (mDiskLruCache != null && !mDiskLruCache.isClosed()) {
                try {
                    mDiskLruCache.delete();
                } catch (Throwable e) {
                    LogUtils.e(e.getMessage(), e);
                }
                mDiskLruCache = null;
                isDiskCacheReadied = false;
            }
        }
        initDiskCache();
    }
 

    public void clearDiskCache(String uri) {
        synchronized (mDiskCacheLock) {
            if (mDiskLruCache != null && !mDiskLruCache.isClosed()) {
                try {
                    mDiskLruCache.remove(uri);
                } catch (Throwable e) {
                    LogUtils.e(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Flushes the disk cache associated with this ImageCache object. Note that this includes
     * disk access so this should not be executed on the main/UI thread.
     */
    public void flush() {
        synchronized (mDiskCacheLock) {
            if (mDiskLruCache != null) {
                try {
                    mDiskLruCache.flush();
                } catch (Throwable e) {
                    LogUtils.e(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * Closes the disk cache associated with this ImageCache object. Note that this includes
     * disk access so this should not be executed on the main/UI thread.
     */
    public void close() {
        synchronized (mDiskCacheLock) {
            if (mDiskLruCache != null) {
                try {
                    if (!mDiskLruCache.isClosed()) {
                        mDiskLruCache.close();
                        mDiskLruCache = null;
                    }
                } catch (Throwable e) {
                    LogUtils.e(e.getMessage(), e);
                }
            }
        }
    }

    private class BitmapMeta {
        public FileInputStream inputStream;
        public byte[] data;
        public long expiryTimestamp;
    }

    

    public class MemoryCacheKey {
        private String uri;
        private String subKey;

        private MemoryCacheKey(String uri, String subKey) {
            this.uri = uri;
            this.subKey = subKey;
        }

      
    }
}

在项目中做下载模块时也遇到线程情况,下载的文件支持开始,暂停,继续,断点续传等功能,当时做暂停(继续)时,采用的是下载对象的一个变量值来进行判断,然后采用线程的sleep来实现暂停功能。

HttpURLConnection mConnection = null;
        URL url = null;
        InputStream inputStream = null;
        RandomAccessFile outputStream = null;
        mModel = params[0];
        try {
//        	url = new URL("https://download.gamm.ztgame.com/apk/lutachuanqi.apk");
        	url = new URL(mModel.getmDownloadUrl());
            mConnection = (HttpURLConnection) url.openConnection();
         
            mConnection.setDoInput(true);
            mConnection.setAllowUserInteraction(true);
            mConnection.setRequestMethod("GET");
            mConnection.setReadTimeout(60000);//
            mConnection.setRequestProperty("User-Agent", "NetFox");
            mConnection.setRequestProperty("Accept-Encoding","identity");
            mConnection.setRequestProperty("Range","bytes=" + mModel.getmDownloadPosition() + "-");
            mConnection.setRequestProperty("Connection","Keep-Alive");//
            mConnection.connect();
            mStateCode = mConnection.getResponseCode();

            inputStream = mConnection.getInputStream();
            length = mConnection.getContentLength() + mModel.getmDownloadPosition();


            File outFile = new File(Environment.getExternalStorageDirectory()
                    .getPath() + PluginDownloadUtil.DOWN_DIR, mModel.getmDownloadName()+".apk");
            if (!outFile.exists()) {
                try {
                    outFile.getParentFile().mkdir();
                    outFile.createNewFile();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
            //
            try {
                outputStream = new RandomAccessFile(outFile, "rwd");
            } catch (FileNotFoundException e) {

                e.printStackTrace();
            }
            //
            outputStream.seek(mModel.getmDownloadPosition());
            byte[] buf = new byte[1024 * 100];
            int read = 0;
            curSize = mModel.getmDownloadPosition();

            //Log.e("--------Task-----------", "-------downstatus----------------" + mModel.getmDownloadName() + ",length = " + mConnection.getContentLength());
            if (mConnection.getContentLength() != -1){
                mModel.getmDatabase().updateInfoById(mModel.getmDownloadId(),
                        DownloadDB.COLUMN_DOWNLOAD_PKG_SIZE, mConnection.getContentLength());


                while (mModel.getmDownloadStatues() < 4
                        && mModel.getmDownloadStatues() > 0) {
                    while ((mModel.getmDownloadStatues() == 2)||(mModel.getmDownloadStatues() == 3)) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    read = inputStream.read(buf);
                    if (read == -1 || mModel.getmDownloadStatues() == 0) {

                        break;
                    }
                    outputStream.write(buf, 0, read);
                    curSize = curSize + read;
                    int progress = (int) ((curSize * 100) / length);
                    publishProgress(progress);
                    mModel.setmDownloadPosition((int) curSize);
                    mModel.getmDatabase().updateInfoById(mModel.getmDownloadId(),
                            DownloadDB.COLUMN_DOWNLOAD_POSITION, (int) curSize);
                    mModel.setmDownloadProgress(progress);
                    mModel.getmDatabase().updateInfoById(mModel.getmDownloadId(),
                            DownloadDB.COLUMN_DOWNLOAD_PROGRESS, progress);

                    if (curSize == length) {
                        Message msg = mUpdateUiHandler.obtainMessage();
                        msg.what = 1;
                        mUpdateUiHandler.sendMessage(msg);
                        mModel.setmDownloadStatues(4);
                        mModel.getmDatabase().updateInfoById(mModel.getmDownloadId(), DownloadDB.COLUMN_DOWNLOAD_STATUES, 4);

                        break;
                    }
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                return "success";
            }else {
                if (mStateCode == 416||mStateCode == 206){
                    mModel.setmDownloadStatues(0);
                    mModel.setmDownloadPosition(0);
                    mModel.setmDownloadProgress(0);

                    mModel.getmDatabase().updateInfoBeanId(mModel.getmDownloadId());
                }

                return "exception";
            }

        } catch (IOException e) {
            e.printStackTrace();
            if (mStateCode == 416||mStateCode == 206){
                mModel.setmDownloadStatues(0);
                mModel.setmDownloadPosition(0);
                mModel.setmDownloadProgress(0);
                mModel.getmDatabase().updateInfoBeanId(mModel.getmDownloadId());
            } else {
                mModel.setmDownloadStatues(0);
                mModel.getmDatabase().updateInfoById(mModel.getmDownloadId(), "download_statues", 0);
            }

            return "exception";
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (mConnection != null) {
            	mConnection.disconnect();
            }

        }















0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:306697次
    • 积分:6192
    • 等级:
    • 排名:第4432名
    • 原创:297篇
    • 转载:108篇
    • 译文:1篇
    • 评论:21条
    最新评论