在java中我们经常会遇到多线程问题,包括线程的互斥,同步,线程通信,线程池等一些问题,也是面试中经常问道的。这里做一个笔记。
本篇主要介绍创建线程的三种方式,后续会陆续介绍同步,线程通信等问题
继承Thread类并复写run()方法,是一种很简单的方式,代码如下:
package thread;/** * Created by qiyei2015 on 2017/2/6. */public class MyThread extends Thread { public MyThread(String name) { super(name); } @Override public void run() { String name = Thread.currentThread().getName(); System.out.PRintln(name + "已经运行"); }}run()方法内就是线程体,可以做我们自己的工作。另外线程的启动是调用start()方法。
import thread.MyThread;public class Main { public static void main(String[] args) { new MyThread("线程一").start(); }}结果: 可以看到线程已经运行起来了。
这个是我们经常使用的方式之一,代码如下:
package thread;/** * Created by qiyei2015 on 2017/2/6. */public class MyTask implements Runnable { @Override public void run() { String name = Thread.currentThread().getName(); System.out.println(name + "已经运行"); }}测试代码如下:
import thread.MyTask;public class Main { public static void main(String[] args) { //new MyThread("线程一").start(); new Thread(new MyTask(),"线程二").start(); }}结果: 一般我们推荐的就是实现Runable接口这种方式来创建线程,这是因为由于java的单继承限制,我们继承了Thread类就不能再继承其他的类了。
我们看到不管是Thread还是Runable接口,其run()都是无返回值的,并且无法抛出异常的,如果我们有需要返回值或者抛出异常怎么办?这个时候就需要用到Callable与Feature了。
先来看类的继承关系
可以看到Callable是一个接口,里面有个V call()方法,这个V就是我们返回值类型,同时还有Future相关的类,注意观察FutureTask类的构造函数,我们发现其中一个构造函数的参数是Callable类型,这里就把两个内联系起来了。Callable与Future的用法如下:
用法一:使用FutureTask来启动Callable线程 实现Callable接口的V call()方法,并构造FutureTask 对象,调用该对象的run()方法
import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;public class Main { public static void main(String[] args) { //new MyThread("线程一").start(); //new Thread(new MyTask(),"线程二").start(); callableTest1(); }private static void callableTest1(){ //这里指定返回String类型 Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { System.out.println("Callable 已经运行啦"); return "this is Callable is running"; } }; FutureTask<String> futureTask = new FutureTask<String>(callable); futureTask.run(); try { if (futureTask.isDone()){ //任务完成 System.out.println(futureTask.get()); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }}结果如下:
可以看到线程已经运行了,并且我们也收到返回值了。其中call()就是我们的线程体。
用法二:使用 ExecutorService线程池来提交Callable任务
这里我们主要用到线程池,有关线程池的问题后面再细讲。这里只需要知道怎么用就行。我们还是使用Future来获取返回的结果,代码如下:
import java.util.concurrent.*;public class Main { public static void main(String[] args) { //new MyThread("线程一").start(); //new Thread(new MyTask(),"线程二").start(); //callableTest1(); callableTest2(); } private static void callableTest2(){ ExecutorService executorService = Executors.newSingleThreadExecutor(); //这里指定返回Integer类型 Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("Callable 已经运行啦"); return 1024; } }; Future<Integer> futureTask = executorService.submit(callable); try { Thread.sleep(100); if (futureTask.isDone()){ System.out.println(futureTask.get()); } } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }}结果:
好,本文到这里就结束了。
新闻热点
疑难解答