在java中比较常用的有三种创建多线程的方式。
方式一:继承Thread类,要重写run方法。
在MyThread类
1 public class MyThread extends Thread { 2 @Override 3 public void run() { 4 for (int i = 0; i < 100 ; i++) {
//获取线程名称 5 System.out.println(getName()+":"+i); 6 } 7 super.run(); 8 } 9 }
测试类:
1 public class MyThreadDemo { 2 public static void main(String[] args) { 3 MyThread my1 = new MyThread(); 4 MyThread my2 = new MyThread(); 5 my1.setName("张飞"); 6 my2.setName("关羽"); 7 8 my1.setDaemon(true); 9 //开启线程 10 my1.start(); 11 my2.start(); 12 //设置主线程名称 13 Thread.currentThread().setName("刘备"); 14 15 for (int i = 0; i < 5; i++) { 16 System.out.println(Thread.currentThread().getName()+":"+i); 17 } 18 } 19 }
常用方法:
public static void sleep(long millis,int nanos) 在指定的毫秒数内让当前正在执行的线程休眠
这里再提一句:start和run方法有什么区别:run方法就是执行括号里的代码 start方法是首先启动了线程,然后由jvm调用run方法。
方式二:
实现Runnable接口,也要重写run方法。创建Thread对象,将Runnable作为参数传递。
1 //测试Runnable 2 public static void testRunnable(){ 3 //创建Runnable对象 4 Runnable r = new Runnable() { 5 6 @Override//run()方法没有返回值,只能通过try抛出异常 7 public void run() { 8 System.out.println("当前线程的名字是:"+Thread.currentThread().getName()); 9 try { 10 Thread.sleep(2000); 11 } catch (InterruptedException e) { 12 // TODO: handle exception 13 } 14 } 15 }; 16 //Thread包装Runnable 17 Thread t = new Thread(r); 18 t.start(); 19 }
方式三:
实现Callable接口。在展示Demo之前,说一说实现这个接口需要用到的类和接口。
ExecutorService(线程池):接口,它的超级接口是Executor。
下面这些是返回ExecutorService对象的方法。
* public static ExecutorService newCachedThreadPool() 创建corePoolSize为0,最大线程数为整型的最大数,线程 keepAliveTime为1分钟,缓存任务的队列为SynchronousQueue的线程池。
* public static ExecutorService newFixedThreadPool(int nThread) 创建固定大小的线程池
* public static ExecutorService newSingleThreadExecutor() 创建大小为1的固定线程池
可以执行Runnable对象或者Callable对象代表的线程。
Future<?> submit(Runnable task)
<T> Future<T> submit(Callable<T> task)
Executors(类):提供了用于此包中所提供的执行程序服务的工厂方法。也就是说可以用它来创建线程池。
Future(接口),API解释:
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。说白了就是获取Callable返回值的对象。
FutureTask(类):它实现的接口:Runnable Future<V> RunnableFuture<V>。
构造方法:
FutureTask(Callable<V> callable)
创建一个 FutureTask,一旦运行就执行给定的 Callable。
FutureTask(Runnable runnable, V result)
创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。
1 //测试Callable,可以通过throws抛出异常 2 public static void testCallable() throws InterruptedException, ExecutionException{ 3 //创建对象 4 Callable<Student> c = new Callable<Test.Student>() { 5 6 @Override 7 //call()方法可以有返回值,并且可以通过throws抛出异常 8 public Student call() throws Exception { 9 System.out.println("当前线程的名称是:"+Thread.currentThread().getName()); 10 Thread.sleep(2000); 11 return new Student("张飞", 30); 12 } 13 }; 14 //包装对象 第一种方法 15 FutureTask<Student> ft = new FutureTask<Student>(c); 16 17 try { 18 //执行线程 19 new Thread(ft).start(); 20 //获取结果 21 System.out.println(ft.get().getName()+ft.get().getAge()); 22 } catch (Exception e) { 23 e.printStackTrace(); 24 } 25 26 //第二种方法 27 //创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 28 ExecutorService es = Executors.newSingleThreadExecutor(); 30 //Executors Executor ExecutorService 31 Future<Student> f = es.submit(new Callable<Student>() { 32 33 @Override 34 public Student call() throws Exception { 35 36 return new Student("关羽", 33); 37 } 38 }); 39 System.out.println(f.get().getName() + f.get().getAge()); 40 41 42 43 }