边读边写【七】 -java 多线程实战【Thread /Executors】
边读边写【7】 ----java 多线程实战【Thread /Executors】
前面2个月一直忙碌,但是还是不忘在iteye 上发发帖子,写写文章。终于这周over了2套系统,剩下的时间基本上修改跟维护了。
在完成的一套“应用安装系统”后对多线程的理解又深了一点。
这里写出来,一来跟大家分享,二来让坛子里的大牛们指教指教,许多不足之处。
ps:看《maven 实战》看着看着就想睡觉,不知为什么?我一般看书很认真的。
ok。看看需求:
首先来实现一个多线程。简单的说就是在一个方法里头要完成6件事,6件事没有直接关联关系。不会因为一件事不完成导致下面的事情无法完成。都完成好了,就执行下一个方法。
线程的俩种实现方式,如果你的代码已经继承其他类了,就实现Runnable借口。这俩种方式的线程都是没有返回值的。
公司的代码不好贴,这里贴个变相的demo.
策略一:
这样做貌似也能达到要求。但是有明显的缺点。
第一:线程同时运行,必须用守护线程去执行线程做完以后将要运行的方法:这是不可取的,守护线程会立刻跟这死掉,如果将要做的事情的需要消耗大量的时间,或者开销的话,那么这个方法是不会正确执行的。【不知道具体原因,希望大鸟能指点迷津。】
第二:程序一执行,各个线程独立跑,守护线程只能监视各个线程的状态而无法获取各个线程所执行的事情是否成功了。这是相当不理想的。
策略二:Callable
使用策略二的好处有:
第一:Callable 的好处是有返回值,也就是说一个线程是否成功完成了他的使命,我们可以从他的返回的结果中【自定义结果】中得知。
第二:ThreadPoolExecutor【写了一些并发包相关的博文放在草稿箱里没有发表出来,主要是怕错误太多 - -,贻笑大方】它提供了一个线程池,使用方法通常使用 Executors 工厂方法配置。 api说:线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。用Executor提交一个带返回值的Callable到ExecutorService里面。返回只类型是Futrue[未来,很有意思]。更有意思的是他会等全部的Callable执行完了以后在往下走,当然需要控制的是:
第一个newCachedThreadPool();他会启动n个线程来完成你的任务。他能自动线程回收。但是他的时间是60s.可以把这个demo跑下,发现让他sleep70秒他可以。这个问题我搞了很久没搞明白【求明白的分享】。所以我没用。用的是.newFixedThreadPool(7)参数能设置他的线程数。
总的来说还是那俩句话,一是分享,一是请教。谢谢
前面2个月一直忙碌,但是还是不忘在iteye 上发发帖子,写写文章。终于这周over了2套系统,剩下的时间基本上修改跟维护了。
在完成的一套“应用安装系统”后对多线程的理解又深了一点。
这里写出来,一来跟大家分享,二来让坛子里的大牛们指教指教,许多不足之处。
ps:看《maven 实战》看着看着就想睡觉,不知为什么?我一般看书很认真的。
ok。看看需求:
首先来实现一个多线程。简单的说就是在一个方法里头要完成6件事,6件事没有直接关联关系。不会因为一件事不完成导致下面的事情无法完成。都完成好了,就执行下一个方法。
线程的俩种实现方式,如果你的代码已经继承其他类了,就实现Runnable借口。这俩种方式的线程都是没有返回值的。
公司的代码不好贴,这里贴个变相的demo.
策略一:
public class TestThread { // private static int i; //这里就相当做事的方法,所以线程都做这一件事,同时做 public void get(long name) { try { Thread.sleep(name); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("-----name-----"+name); i++; } //全部做完了。 public int over(int n){ System.out.println("---over--"+n); return n; } //正开始做 public void ing (){ final TestThread td = new TestThread(); Thread tr4 = new Thread(new Runnable(){ @Override public void run() { td.get(1500L); } }); tr4.start(); new Thread(){ public void run (){ td.get(500L); } }.start(); new Thread(){ public void run (){ td.get(100L); } }.start(); } public void show(){ System.out.println("=======show()========"); } public static void main(String[] args) { //调用 final TestThread ted = new TestThread(); ted.ing(); //来一个守护线程,监视看是不是所以的事情都做完了。做完了守护线程也跟着挂了 Thread tt = new Thread(){ public void run (){ while(true){ try { //守护线程每100ms检查一下各个线程的完成状况 Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } //方法运行了3此,代码多做了,这是守护线程也要挂了,挂之前。。。。。 if(i==3){ ted.show(); ted.over(1); } } } }; tt.setDaemon(true); tt.start(); //ted.show(); 这个方法会同是运行 } }
这样做貌似也能达到要求。但是有明显的缺点。
第一:线程同时运行,必须用守护线程去执行线程做完以后将要运行的方法:这是不可取的,守护线程会立刻跟这死掉,如果将要做的事情的需要消耗大量的时间,或者开销的话,那么这个方法是不会正确执行的。【不知道具体原因,希望大鸟能指点迷津。】
第二:程序一执行,各个线程独立跑,守护线程只能监视各个线程的状态而无法获取各个线程所执行的事情是否成功了。这是相当不理想的。
策略二:Callable
public class HasValueThread { public void a(){ Callable ca1 = new Callable(){ @Override public Object call() throws Exception { System.out.println("==yes==="); return true; } }; Date d1 = new Date(); System.out.println("d1"+d1.toLocaleString()); //ExecutorService exec = Executors.newCachedThreadPool();//创建线程池 ExecutorService exec = Executors.newFixedThreadPool(7);//创建线程池 Callable c1 = new MyCallable("A",1000); Callable c2 = new MyCallable("B",5000); Callable c3 = new MyCallable("c",15000); Future f1 = exec.submit(c1); Future f2 = exec.submit(c2); Future f4 = exec.submit(c3); Future f3 = exec.submit(ca1); try { System.out.println(f1.get().toString()+System.currentTimeMillis()); System.out.println(f2.get().toString()+System.currentTimeMillis()); System.out.println(f4.get().toString()+System.currentTimeMillis()); System.out.println(f3.get().toString()+System.currentTimeMillis()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } exec.shutdown(); } public static void main(String[] args) { new HasValueThread().a(); System.out.println("------"); } } class MyCallable implements Callable{ private String oid; private long n; MyCallable(String oid,long n) { this.oid = oid; this.n = n; } @Override public Object call() throws Exception { Date d2 = new Date(); System.out.println("d2"+d2.toLocaleString()); Thread.sleep(n); return oid+"任务返回的内容"; } }
使用策略二的好处有:
第一:Callable 的好处是有返回值,也就是说一个线程是否成功完成了他的使命,我们可以从他的返回的结果中【自定义结果】中得知。
第二:ThreadPoolExecutor【写了一些并发包相关的博文放在草稿箱里没有发表出来,主要是怕错误太多 - -,贻笑大方】它提供了一个线程池,使用方法通常使用 Executors 工厂方法配置。 api说:线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行任务集时使用的线程)的方法。每个 ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。用Executor提交一个带返回值的Callable到ExecutorService里面。返回只类型是Futrue[未来,很有意思]。更有意思的是他会等全部的Callable执行完了以后在往下走,当然需要控制的是:
//ExecutorService exec = Executors.newCachedThreadPool();//创建线程池 ExecutorService exec = Executors.newFixedThreadPool(7);//创建线程池
第一个newCachedThreadPool();他会启动n个线程来完成你的任务。他能自动线程回收。但是他的时间是60s.可以把这个demo跑下,发现让他sleep70秒他可以。这个问题我搞了很久没搞明白【求明白的分享】。所以我没用。用的是.newFixedThreadPool(7)参数能设置他的线程数。
总的来说还是那俩句话,一是分享,一是请教。谢谢