标签:
有时,我们需要在一个程序中同时并行的处理多个任务,如播放器一边要播放音乐同时还要不断更新画面显示,或者是一边执行耗时任务,UI还能一边继续响应各种事件。还有的时候,一个任务需要很长时间才能完成,如果分成多份一起执行,可以极大的缩短需要的时间。多线程可以很好的解决这类问题。
一个程序(进程)如果可以同时执行多个任务,每个并行的任务都是通过一个线程来完成,这就是一个多线程程序。进程拥有自己的一整套数据(变量),各个线程共享进程的数据,线程间通信比进程间通信更简单,线程开销比进程小。
Java中为多线程任务提供了很多的类。包括最基础的Thread类、Runnable等接口,用于线程同步的锁、阻塞队列、同步器,使用线程池的执行器、执行框架,还有可以在多线程中使用的线程安全集合等。
Runnable接口和Thread类是实现多线程最基础的方式。
方式一:把要在新线程中执行的代码封装在Runnable对象的run()方法中,将Runable对象做为参数构造Thread对象,调用Thread对象的start()方法,并行任务就会在一个新的线程中开始执行,而当前线性继续执行后面的代码直至结束。
方式二:从Thead派生子类,重写Thread类的run()方法,在其中放置在要新线程中执行的代码,然后创建Thread子类对象并调用start()方法。这种方式可以省去Runnable包装类,但是却要创建一个Thread的子类。
推荐使用方法一,因为方法二把线程对象和具体任务一一绑定了,要执行1000个任务就得创建等量的线程,代价太大。应该把具体任务和用于执行任务的线程对象分离开,任务就封装在Runnbale对象中,这样就可使用线程池,用固定数量的线程来执行数量巨大的任务。
必须调用Thread类的start()方法才能开启新线程。直接调用Thread或Runnable对象的run()方法都只是在当前线程中执行任务。
Thread
Runnable 接口 包装在新线程中执行的内容
示例代码
class MyThread extends Thread { private int begin; public void setCountStart(int begin) { this.begin=begin; } @Override public void run() { try { int end=begin+100; for(int i=begin; i<end; i++){ System.out.println("sub: "+i); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } } MyThread t=new MyThread(); t.setCountStart(200); t.start(); for(int i=0; i<100; i++){ System.out.println("main: "+i); Thread.sleep(1000); }
class MyTask implements Runnable { private int begin=0; public MyTask(int s){begin=s;} @Override public void run() { try { int end=begin+100; for(int i=begin; i<end; i++){ System.out.println("sub: "+i); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread t=new Thread(new MyTask(123)); t.start(); for(int i=0; i<100; i++){ System.out.println("main: "+i); Thread.sleep(1000); if(i==10) t.stop(); }
自动结束
Thread或Runnable对象的run()方法包装了新线程中执行的代码,在run()方法中遇到下面的情况,线程会自动终止。
强制结束
void interrupt()方法和InterruptedException特别说明
(注意也存在不能被中断的阻塞IO调用,最好不要使用不可中断的方法)。
既然只要抛出InterruptedException,中断状态肯定已经被清理了,这种情况只有InterruptedException这个异常是我们知道有中断请求的唯一标识了,一定要向外层通知有中断发生,千万不要再把这个异常压制住,否则怎么调用interrupt()方法请求中断都不会有什么卵用,线程中外层的代码压根不知道有中断这回事,照常运行。将这个中断请求通知给外层有两种方式:
直接调用stop()方法见前一段实例代码。采用中断方式实例如下:
class MyInterruptableCheckTask implements Runnable { private int begin=0; public MyInterruptableCheckTask(int s){begin=s;} @Override public void run() { int end = begin + 3000000; for (int i = begin; i < end && !Thread.currentThread().isInterrupted(); i++) { System.out.println("sub: " + i); } if (Thread.currentThread().isInterrupted()) System.out.println("sub thread is interrupted"); else System.out.println("sub natural stop"); } }; Thread t=new Thread(new MyInterruptableCheckTask(111)); t.start(); for(int i=0; i<10; i++){ System.out.println("main: "+i); Thread.sleep(1000); if(i==5) t.interrupt(); }
class MyInterruptableExceptionTask implements Runnable { private int begin=0; public MyInterruptableExceptionTask(int s){begin=s;} @Override public void run() { try { int end=begin+10; for(int i=begin; i<end; i++){ System.out.println("sub: "+i); Thread.sleep(1000); //如果设置中断时正在sleep,或设置完中断后一个循环里遇到sleep,都会抛出InterruptedException异常,不需要再手动检测中断状态了 } } catch (InterruptedException e) { System.out.println("the call Thread.sleep(n) is interrupted by InterruptedExcetpion"); Thread.currentThread().interrupt(); //产生InterruptedException异常时中断状态被清除,所有要重新设置中断或将中断异常向外抛出供后续代码检测是否发生了中断 } if(Thread.currentThread().isInterrupted()) System.out.println("sub thread is interrupted"); else System.out.println("sub natural stop"); } }; Thread t=new Thread(new MyInterruptableExceptionTask(111)); t.start(); for(int i=0; i<10; i++){ System.out.println("main: "+i); Thread.sleep(1000); if(i==5) t.interrupt(); }
AWT事件分配线程
标签:
原文地址:http://www.cnblogs.com/pixy/p/4790450.html