Java多线程的实现java
用多线程只有一个目的:更好的利用cpu资源.烧水的例子.(当洗杯子花5分钟,线程要停5分钟等待返回结果才能进行后续的烧水操做,新开一个线程执行洗杯子操做)。web
1、关于线程的一些概念算法
2、Java多线程的实现安全
一、继承Thread类建立线程多线程
Thread类本质上是实现了Runnable接口,启动该线程的惟一方法是start()方法,并发
public class MyThread extends Thread{ //普通的调用方法,定义任务要完成的工做. @Override public void run() { System.out.println("新线程正在执行,处理相关的逻辑!"); } } public class Test { public static void main(String[] args) { //实例化对象 MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); //开启新的线程,分配新的资源 myThread1.start(); myThread2.start(); } }
二、实现Runnable接口建立线程框架
java中是单继承的,若是继承了一个类,就不能直接继承Thread类,须要实现Runnable接口的方式达到开启新线程的目的.异步
public class MyThread implements Runnable { //普通的调用方法,定义任务要完成的工做. @Override public void run() { System.out.println("新线程正在执行,处理相关的逻辑!"); } } public class Test { public static void main(String[] args) { MyThread myThread = new MyThread(); Thread thread =new Thread(myThread); //开启新的线程,分配新的资源 thread.start(); } }
三、实现Callable接口ide
Callable接口的call()方法相似run()方法,都是定义任务要完成的工做.主要不一样点是call()方法是有返回值的、能够抛出异常。Callable类型的任务能够有两种方法开启执行.性能
方法一:借助FutureTask执行(FutureTask、Callable)
将Callable接口对象放到FutureTask对象中,FutureTask的get()方法,能够获取返回值.
public class MyCallableTask implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("新线程正在执行,处理相关的逻辑!"); Thread.sleep(3000); int sum = 0; for(int i=0;i<100;i++) { sum += i; } return sum; } } public class Test { public static void main(String[] args) { Callable<Integer> mycallabletask = new MyCallableTask(); //由Callable<Integer>建立一个FutureTask<Integer>对象: FutureTask<Integer> futuretask = new FutureTask<Integer>(mycallabletask); //注释:FutureTask<Integer>是一个包装器,它经过接受Callable<Integer>来建立,它同时实现了Future 和Runnable接口。 //由FutureTask<Integer>建立一个Thread对象: Thread oneThread = new Thread(futuretask); oneThread.start(); try { //经过futuretask中get()方法能够获得MyCallableTask的call()运行结果. //须要使用时获取出来,不然出现堵塞,本线程要等待新线程执行完返回结果才执行 Integer i = futuretask.get(); } catch (Exception e) { e.printStackTrace(); } } }
方法二:借助线程池来运行 (ExecutorService、Callable、Future)
ExecutorService、Callable、Future三个接口实际上都是属于Executor框架。
执行Callable任务后,能够获取一个Future的对象,在该对象上调用get()就能够获取到Callable任务返回的Object了。
public class MyCallableTask implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("新线程正在执行,处理相关的逻辑!"); Thread.sleep(3000); int sum = 0; for(int i=0;i<100;i++) { sum += i; } return sum; } } public class Test { public static void main(String[] args) { int taskSize = 5; //建立线程池 ExecutorService threadPool = Executors.newCachedThreadPool(taskSize); //提交一个Callable任务,返回一个Future类型 Future<Integer> future = threadPool.submit(new MyCallableTask()); try { Thread.sleep(3000);//模拟本线程的一些任务 //获取执行结果get方法是阻塞的 System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); } } }
采用匿名类直接新建Callable接口
public class Test{ public static void main(String[] args) { // 建立线程池 ExecutorService threadPool = Executors.newCachedThreadPool(); // 提交一个Callable任务,返回一个Future类型 Future<Integer> future = threadPool.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("新线程正在执行,处理相关的逻辑!"); Thread.sleep(3000); int sum = 0; for (int i = 0; i < 100; i++) { sum += i; } return sum; } }); try { Thread.sleep(3000);//模拟本线程的一些任务 //获取执行结果 System.out.println(future.get()); } catch (Exception e) { e.printStackTrace(); } } }
3、使用场景
1、Tomcat内部采用了多线程,上百个用户同时访问同一个web应用,都会新开一个线程,调用到Servlet程序。若是不使用多线程,将串行操做,客户端将等待别人执行完才能访问。
2、异步请求,有两个任务Task a和Task b,单线程只能先进行a再进行b。
3、须要知道执行进度,好比说咱们常看到的进度条,任务执行到必定进度给new 一个变量,给变量+1.新开一个线程去轮询这个变量,反馈给客户端,这样就能够看到进度状况.
总之,不少地方都用到了多线程,多线程是为了充分利用cpu资源,当你发现一个业务逻辑执行效率特别低,耗时长,能够考虑使用多线程.