转载:http://marshal.easymorse.com/archives/3081
java5开始,增加了concurrent api,用于并发处理。比如起多个线程并发从网络上下载图片,然后在本地显示。
这里写个简单的代码,来说明如何使用concurrent api提供的线程连接池。
运行结果类似这样:
start do 1 task … >>main thread end. start do 2 task … start do 1 finished. start do 3 task … start do 2 finished. start do 3 finished.
这里的task1到task3,都做的同样的事情,让它所属的线程休眠2000ms:
private static void doSomething(int id) { System.out.println("start do " + id + " task …"); try { Thread.sleep(1000 * 2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("start do " + id + " finished."); }
如果没有java自带的这个api,需要自己或者使用不标准的第三方线程池api。用concurrent api写起来很简洁:
public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(new Runnable() { @Override public void run() { doSomething(1); } }); executorService.submit(new Runnable() { @Override public void run() { doSomething(2); } }); executorService.submit(new Runnable() { @Override public void run() { doSomething(3); } }); executorService.shutdown(); System.out.println(">>main thread end."); }
首先,创建了一个线程池,里面有2个线程:
ExecutorService executorService = Executors.newFixedThreadPool(2);
然后,通过submit()方法,提交一个Runnable的实例,这个实例将交由线程池中空闲的线程执行。
在main线程中直接运行了:
executorService.shutdown();
不必担心,线程池不会直接关闭的,只有当它执行完所有提交的任务后才会关闭。如果不写这行,在本例中,应用将不会停止,因为虽然main线程(就是运行main方法的线程,也叫主线程)退出了,但是线程池中依然有线程运行,因此应用(进程)不会退出。
在android异步加载ListView中的图片中使用异步方式加载的图片,当时要的急,写的很粗糙,是为每个图片加载一个线程来实现的。
可以用java concurrent很简明的实现类似功能,并且用到线程池。
这里加载的图片,都是从网上直接获取的。如果用android的UI线程,则需要图片全部加载后才能显示界面。
这里使用了concurrent api通过后台线程并发获取,本例中线程池中只有一个线程,可以设置为多个以加快加载速度。可参见使用java concurrent处理并发需求中的简单示例了解concurrent api的基本机制。
public class LazyLoadImageActivity extends Activity { private ExecutorService executorService = Executors.newFixedThreadPool(1); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); loadImage("http://www.chinatelecom.com.cn/images/logo_new.gif", R.id.image1); loadImage("http://www.baidu.com/img/baidu_logo.gif", R.id.image2); loadImage("http://cache.soso.com/30d/img/web/logo.gif", R.id.image3); } @Override protected void onDestroy() { executorService.shutdown(); super.onDestroy(); } private void loadImage(final String url, final int id) { final Handler handler=new Handler(); executorService.submit(new Runnable() { @Override public void run() { try { final Drawable drawable = Drawable.createFromStream( new URL(url).openStream(), "image.png"); handler.post(new Runnable() { @Override public void run() { ((ImageView) LazyLoadImageActivity.this .findViewById(id)) .setImageDrawable(drawable); } }); } catch (Exception e) { throw new RuntimeException(e); } } }); } }
备注:
handler.post(new Runnable() { @Override public void run() { ((ImageView) LazyLoadImageActivity.this .findViewById(id)) .setImageDrawable(drawable); } });API中的解释:
Causes the Runnable r to be added to the message queue. The runnable will be run on the thread to which this handler is attached.
Android中通过Handler对象的post()方法将一个线程加入线程队列的时候,直接调用了Runnable的run()方法,并没有调用start()方法;也就是说Run()方法所执行的内容还是在
主线程中进行,post()方法并没有启动新的线程;
利用handler.post()更新UIhttp://hi.baidu.com/xcmxjge/blog/item/d51d5034d399fd345bb5f52e.html
1.创建一个Handler 2.调用Handler.post(Runnable r)方法 3.Runnable运行在UI所在线程,所以可以直接调用View.invalidate()
public class TestHandler extends Activity { private MyView myView; private Handler mHandler; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myView = new MyView(this); //创建一个Handler mHandler = new Handler(); //调用Handler.post(Runnable r)方法 mHandler.post(new Runnable(){ @Override public void run() { //直接调用View.invalidate(),更新组件 myView.invalidate(); //延迟5毫秒后执行线程 mHandler.postDelayed(this, 5); } }); setContentView(myView); } class MyView extends View{ private float x = 0f; public MyView(Context context) { super(context); } protected void onDraw(Canvas canvas) { super.onDraw(canvas); x+=1; Paint mPaint = new Paint(); mPaint.setColor(Color.BLUE); canvas.drawRect(x, 40, x+40, 80, mPaint); } } }在新线程里更新UI,可以直接postInvalidate() ,不需要转到UI线程再进行刷新
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); myView = new MyView(this); this.setContentView(this.myView); new Thread(new myThread()).start(); } class myThread implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { try { myView.postInvalidate(); Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }