JAVA多线程

来源:互联网 发布:2018网络教育报名时间 编辑:程序博客网 时间:2024/06/07 05:21

一:JAVA实现多线程方式有三种。
1:实现runable接口。
2:类继承Tread类,实质Thread也是实现了runable接口。
3:使用ExecutorService。

1:继承Thread类:

package com.ida.console.web.controller.usercert;public class ThreadTest extends Thread {    private String name;    public ThreadTest(String name) {        this.name = name;    }    @Override    public void run() {        System.out.println(Thread.currentThread().getName())//当前线程        System.out.println(name);    }    public static void main(String[] args) {        ThreadTest thread1 = new ThreadTest("1");        ThreadTest thread2 = new ThreadTest("2");        ThreadTest thread3 = new ThreadTest("3");        thread1.start();        thread2.start();        thread3.start();    }}

上面的代码启动了三个线程,运行结果 123、231等没有顺序。

2:实现runable接口

package com.ida.console.web.controller.usercert;public class RunableTest implements Runnable {    private String name;    public RunableTest(String name) {        this.name = name;    }    @Override    public void run() {    System.out.println(Thread.currentThread().getName())//当前线程        System.out.println(name);    }    public static void main(String[] args) {        Thread thread1 = new Thread(new RunableTest("1"));        Thread thread2 = new Thread(new RunableTest("2"));        Thread thread3 = new Thread(new RunableTest("3"));        thread1.start();        thread2.start();        thread3.start();    }}

上面的代码启动了三个线程,运行结果 123、231等没有顺序。

继承Thread和实现runable都能实现多线程:
比较下面两个例子
1:

package com.ida.console.web.controller.usercert;public class ThreadTest extends Thread {    private int a = 1000;    @Override    public void run() {        while (a > 0) {        System.out.println(Thread.currentThread().getName())//当前线程            System.out.println(a--);        }    }    public static void main(String[] args) {        ThreadTest thread1 = new ThreadTest();        ThreadTest thread2 = new ThreadTest();        ThreadTest thread3 = new ThreadTest();        thread1.start();        thread2.start();        thread3.start();    }}

2:

package com.ida.console.web.controller.usercert;public class RunableTest implements Runnable {    private int a = 1000;    @Override    public void run() {        while (a > 0) {        System.out.println(Thread.currentThread().getName())//当前线程            System.out.println(a--);        }    }    public static void main(String[] args) {        RunableTest runableTest = new RunableTest();        Thread thread1 = new Thread(runableTest);        Thread thread2 = new Thread(runableTest);        Thread thread3 = new Thread(runableTest);        thread1.start();        thread2.start();        thread3.start();        或者        for(int i=0;i<3;i++){            Thread thread = new Thread(runableTest);            thread.start();        }    }}

两个都是启动三个线程,但是第一个会执行打印出3000条数据,也就是每个线程都会执行一遍run,第二个只会打印出1000条数据,因为第一个实例化了三个对象,第二个实例化一个对象,启动三个线程共享run方法。如果是一个买票系统,就必须使用第二种。本来只有1000张票,第一种卖出了3000张,是错误的。合理选择应用。所以程序开发中只要是多线程肯定永远以实现Runnable接口为主:

  1. 避免点继承的局限,一个类可以继承多个接口。
  2. 适合于资源的共享

3:ExecutorService实现
ExecutorService是一种异步执行的多线程,可以让线程在后台执行,实现ExecutorService 就是创建线程池。主要有三种方式:
1:newCachedThreadPool,缓存型线程池,使用时首先查询缓存池有没有建立空闲的线程,有的话就使用,没有就新建一个并加入到线程池,没考虑到服务器的压力。用于执行异步周期很短的任务。线程池中的线程如果没有使用会在60S后移除线程池。不用担心线程不会结束。

2:newFixedThreadPool是创建一个固定线程数量的线程池,每一个任务都会创建一个线程,直到达到固定的数量,后面的任务等待线程池中的线程任务处理完后,又补充一个新任务线程进来。

3:newSingleThreadExecutor创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

4:newScheduledThreadPool创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。(没有使用过)

使用方法:
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newFixedThreadPool(10);
ExecutorService executorService3 = Executors.newScheduledThreadPool();
ExecutorService executorService4 = Executors.newCachedThreadPool();

将任务委托给ExecutorService有几种不同的方式。
1:execute(Runnable)

ExecutorService executorService = Executors.newSingleThreadExecutor();  executorService.execute(new Runnable() {      public void run() {          System.out.println("。。。");      }  });  executorService.shutdown();  

这种方式是没有返回值的。

2:submit(Runnable)

Future future = executorService.submit(new Runnable() {      public void run() {          System.out.println("Asynchronous task");      }  });  //如果任务结束执行则返回 null  System.out.println("future.get()=" + future.get());  

这种方式会返回一直future对象,可以判断任务是否结束,如果任务结束则返回 null

3:submit(Callable)

List<Future<String>> resultList = new ArrayList<Future<String>>();   Future future = executorService.submit(new Callable(){      public Object call() throws Exception {          System.out.println("Asynchronous Callable");          return "Callable Result";      }  });    resultList.add(future);for (Future<String> fs : resultList){                   try{                       while(!fs.isDone);//Future返回如果没有完成,则一直循环等待,直到Future返回完成                      System.out.println(fs.get());     //打印各个线程(任务)执行的结果                   }catch(InterruptedException e){                       e.printStackTrace();                   }catch(ExecutionException e){                       e.printStackTrace();                   }finally{                       //启动一次顺序关闭,执行以前提交的任务,但不接受新任务                      executorService.shutdown();                   }           }  

这种方式可以获取返回的结果。

4:invokeAny(…)

ExecutorService executorService = Executors.newSingleThreadExecutor();  Set<Callable<String>> callables = new HashSet<Callable<String>>();  callables.add(new Callable<String>() {      public String call() throws Exception {          return "Task 1";      }  });  callables.add(new Callable<String>() {      public String call() throws Exception {          return "Task 2";      }  });  callables.add(new Callable<String>() {      public String call() throws Exception {          return "Task 3";      }  });  String result = executorService.invokeAny(callables);  System.out.println("result = " + result);  executorService.shutdown();  

方法 invokeAny() 接收壹個包含 Callable 对象的集合作为参数。调用该方法不会返回 Future 对象,而是返回集合中某壹個 Callable 对象的结果,而且无法保证调用之后返回的结果是哪壹個 Callable,只知道它是这些 Callable 中壹個执行结束的 Callable 对象。

5:invokeAll(…)

package com.ida.console.web.controller.usercert;import java.util.HashSet;import java.util.List;import java.util.Set;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class Test6 {    public static void main(String[] args) {        ExecutorService executorService = Executors.newSingleThreadExecutor();        Set<Callable<String>> callables = new HashSet<Callable<String>>();        callables.add(new Callable<String>() {            public String call() throws Exception {                System.out.println(Thread.currentThread().getName());                return "Task 1";            }        });        callables.add(new Callable<String>() {            public String call() throws Exception {                System.out.println(Thread.currentThread().getName());                return "Task 2";            }        });        callables.add(new Callable<String>() {            public String call() throws Exception {                System.out.println(Thread.currentThread().getName());                return "Task 3";            }        });        List<Future<String>> result = null;        try {            result = executorService.invokeAll(callables);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        for (Future<String> future : result) {            try {                System.out.println(future.get());            } catch (InterruptedException | ExecutionException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }        executorService.shutdown();    }}

方法 invokeAll() 会调用存在于参数集合中的所有 Callable 对象,并且返回壹個包含 Future 对象的集合,你可以通过这個返回的集合来管理每個 Callable 的执行结果。
需要注意的是,任务有可能因为异常而导致运行结束,所以它可能并不是真的成功运行了。但是我们没有办法通过 Future 对象来了解到这個差异。

Executors关闭:

当使用 ExecutorService 完毕之后,我们应该关闭它,这样才能保证线程不会继续保持运行状态。
举例来说,如果你的程序通过 main() 方法启动,并且主线程退出了你的程序,如果你还有一个活动的 ExecutorService 存在于你的程序中,那么程序将会继续保持运行状态。存在于 ExecutorService 中的活动线程会阻止Java虚拟机关闭。
为了关闭在 ExecutorService 中的线程,你需要调用 shutdown() 方法。ExecutorService 并不会马上关闭,而是不再接收新的任务,一但所有的线程结束执行当前任务,ExecutorServie 才会真的关闭。所有在调用 shutdown() 方法之前提交到 ExecutorService 的任务都会执行。
如果你希望立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这各方法会尝试马上关闭所有正在执行的任务,并且跳过所有已经提交但是还没有运行的任务。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 淘宝上买了假货找不到商家怎么办 魅蓝手机一直在开机画面怎么办 在实体店买的手机想退怎么办 淘宝买了东西发货了不想要了怎么办 快递已经发货了不想要了怎么办 锤子手机买了不到十天碎屏了怎么办 唯品会新人专享优惠卷过期了怎么办 我微信被系统说赌博登陆不起怎么办 平湖新居民积分卡怎么办办好办吗 电话卡插上去只能打紧急电话怎么办 不小心充错q币了怎么办 液相色谱柱堵了怎么办处理柱子 扣扣空间宠物消消87关怎么办 微信钱包里的钱忘记密码了怎么办 支付宝绑定银行卡要验证码怎么办 微信红包超出20万限额怎么办 微信充电信的号码话费没到账怎么办 农业银行手机银行转账转错了怎么办 微信钱包里的零钱不见了怎么办 买家说支付宝没钱要微信付钱怎么办 微信红包没绑卡密码忘了怎么办 手机微信红包密码忘了怎么办 qq账号忘了怎么办什么也没绑定 手机银行转账名字对卡号错了怎么办 手机夸行转账卡号输入错了怎么办 移动开通了20元流量卡怎么办? 联通手机充值卡网上充值话费怎么办 提现金额和实际到账不一样怎么办 二冲踏板冷车加油熄火怎么办? qq被盗绑定了别人的银行卡怎么办 如何更改微信支付密码忘记了怎么办 微信钱包没绑银行卡忘记密码怎么办 微信密码忘记了也没绑银行卡怎么办 微信支付密码忘记了没银行卡怎么办 想找回原来的k歌忘了密码怎么办 手机微信钱包支付密码忘了怎么办 微信支付账户被注销了怎么办 微信钱包密码忘了怎么办没绑银行卡 微信钱包密码忘了怎么办不用银行卡 企业网银密码输入三次错误怎么办 微信密码不知道手机也停用了怎么办