[多线程] 新建线程以及线程的运行

1、如何新建一个线程

/**
 * 继承Thread类实现线程
 *
 */
public class CreateByExtends extends Thread {
    @Override
    public void run() {
        System.out.println("Thread By Extends Thread");
        for (int i = 0; i < 10; i++) {
            System.out.println("Thread:" + i + "次");
        }
    }
}
/**
 * 通过实现Runnable接口实现线程
 * 
 * @author ss
 *
 */
public class CreateByImplement implements Runnable {
    @Override
    public void run() {
        System.out.println("Thread By implements Runnable");
        for (int i = 0; i < 10; i++) {
            System.out.println("Runnable:" + i + "次");
        }
    }
}

 

2、对线程进行调用

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         /**
 4          * 通过继承Thread类的线程
 5          */
 6         Thread t1 = new CreateByExtends();
 7         
 8         /**
 9          * 通过实现Runnable接口的线程
10          */
11         Runnable r1=new CreateByImplement();
12         /**
13          * 两个线程随机获得时间片,顺序随机
14          */
15         t1.start();
16         new Thread(r1).start();
17         
18     }
19 }

(1)通过start()方法进行线程调用,实现Runnable接口的线程,必须将Runnable作为Thread类的参数,然后通过Thread的start方法来创建一个新线程来执行该子任务。如果调用Runnable的run方法的话,是不会创建新线程的,这根普通的方法调用没有任何区别。  事实上,查看Thread类的实现源代码会发现Thread类是实现了Runnable接口的

(2)线程在系统中通过获取时间片的方式运行,所以顺序是随机的

输出的结果为:

Thread By Extends Thread
Thread By implements Runnable
Thread:0次
Runnable:0次
Thread:1次
Thread:2次
Thread:3次
Thread:4次
Runnable:1次
Thread:5次
Runnable:2次
Runnable:3次
Runnable:4次
Runnable:5次
Runnable:6次
Runnable:7次
Runnable:8次
Thread:6次
Runnable:9次
Thread:7次
Thread:8次
Thread:9次

 

那如果我们直接调用线程中的run()方法呢:

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         /**
 4          * 通过继承Thread类的线程
 5          */
 6         Thread t1 = new CreateByExtends();
 7         
 8         /**
 9          * 通过实现Runnable接口的线程
10          */
11         Runnable r1=new CreateByImplement();
12 
13         //如果调用线程的run方法
14         t1.run();
15         new Thread(r1).run();
16     }
17 }

 

运行结果为:

Thread By Extends Thread
Thread:0次
Thread:1次
Thread:2次
Thread:3次
Thread:4次
Thread:5次
Thread:6次
Thread:7次
Thread:8次
Thread:9次
Thread By implements Runnable
Runnable:0次
Runnable:1次
Runnable:2次
Runnable:3次
Runnable:4次
Runnable:5次
Runnable:6次
Runnable:7次
Runnable:8次
Runnable:9次

 

(1)这里线程运行的结果是按顺序的,所以我们可以得知,我们只是调用了run()方法而已,并不是两个线程。

(2)通过run方法调用并不会创建新的线程,而是在主线程中直接运行run方法,跟普通的方法调用没有任何区别;

(3)新线程创建的过程不会阻塞主线程的后续执行

 

通过两种方式创建线程有什么区别呢?

直接继承Thread类的话,可能比实现Runnable接口看起来更加简洁,但是由于Java只允许单继承,所以如果自定义类需要继承其他类,则只能选择实现Runnable接口。

 

其他实现线程的方法:

使用ExecutorService、Callable、Future实现有返回结果的多线程

可返回值的任务必须实现Callable接口,类似的,无返回值的任务必须Runnable接口。

3、通过实现Callable接口,实现线程:

 1 /**
 2  * 通过实现Callable接口实现有返回结果的线程
 3  *
 4  */
 5 public class CreateByCallable implements Callable<Object>{
 6 
 7     @Override
 8     public Object call() throws Exception {
 9         System.out.println("Thread By implements Callable<V> ");
10         for(int i=0;i<10;i++){
11             System.out.println("Callabel<V>:"+i+"次");
12         }
13         return "call方法执行结束,返回这句话";
14     }
15 
16 }

 

调用线程:

 1 public class Test02 {
 2     public static void main(String[] args) {
 3 
 4         /**
 5          * 通过实现Callable<V>接口实现的线程
 6          */
 7         Callable<Object> c1 = new CreateByCallable();
 8 
 9         // 调用实现Callable接口的线程,需要使用FutureTask实现类的支持,用于接受结果
10         FutureTask<Object> future = new FutureTask<>(c1);
11 
12         new Thread(future).start();
13 
14         // 接受线程运行后的结果
15         try {
16             Object result = future.get();// FutureTask可用于闭锁,类似于CountDownLatch的作用
17             System.out.println(result.toString());
18         } catch (InterruptedException | ExecutionException e) {
19             e.printStackTrace();
20         }
21 
22     }
23 }

 

结果:

Thread By implements Callable<V> 
Callabel<V>:0次
Callabel<V>:1次
Callabel<V>:2次
Callabel<V>:3次
Callabel<V>:4次
Callabel<V>:5次
Callabel<V>:6次
Callabel<V>:7次
Callabel<V>:8次
Callabel<V>:9次
call方法执行结束,返回这句话

 

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。

 1     public static void main(String[] args) {
 2         
 3         int taskSizes=5;
 4         //创建一个线程池
 5         ExecutorService pool=Executors.newFixedThreadPool(taskSizes);
 6         //创建有多个返回值的任务
 7         List<Future> list=new ArrayList<Future>();
 8         for(int i=0;i<taskSizes;i++){
 9             Callable c=new CreateByCallable();
10             Future f=pool.submit(c);
11             list.add(f);
12         }
13         //关闭线程池
14         pool.shutdown();
15         
16         for(Future f:list){
17             try {
18                 System.out.println(f.get().toString());
19             } catch (InterruptedException|ExecutionException e) {
20                 e.printStackTrace();
21             }
22         }
23     }

 

运行结果:

Thread By implements Callable<V> 
Thread By implements Callable<V> 
Thread By implements Callable<V> 
Callabel<V>:0次
Callabel<V>:0次
Callabel<V>:0次
Callabel<V>:1次
Callabel<V>:2次
Callabel<V>:3次
Callabel<V>:4次
Callabel<V>:1次
Callabel<V>:5次
Thread By implements Callable<V> 
Callabel<V>:1次
Callabel<V>:0次
Callabel<V>:6次
Callabel<V>:2次
Callabel<V>:7次
Callabel<V>:1次
Callabel<V>:2次
Callabel<V>:2次
Callabel<V>:8次
Callabel<V>:3次
Callabel<V>:9次
Callabel<V>:3次
Callabel<V>:4次
Callabel<V>:3次
Callabel<V>:5次
Callabel<V>:4次
Callabel<V>:5次
Callabel<V>:6次
Callabel<V>:6次
Callabel<V>:4次
Callabel<V>:7次
Callabel<V>:7次
Callabel<V>:8次
Callabel<V>:5次
Callabel<V>:9次
Callabel<V>:8次
Callabel<V>:9次
Callabel<V>:6次
Callabel<V>:7次
Callabel<V>:8次
Callabel<V>:9次
Thread By implements Callable<V> 
call方法执行结束,返回这句话
Callabel<V>:0次
call方法执行结束,返回这句话
call方法执行结束,返回这句话
call方法执行结束,返回这句话
Callabel<V>:1次
Callabel<V>:2次
Callabel<V>:3次
Callabel<V>:4次
Callabel<V>:5次
Callabel<V>:6次
Callabel<V>:7次
Callabel<V>:8次
Callabel<V>:9次
call方法执行结束,返回这句话

 

上述代码中Executors类,提供了一系列工厂方法用于创先线程池,返回的线程池都实现了ExecutorService接口。

public static ExecutorService newFixedThreadPool(int nThreads) 

创建固定数目线程的线程池。

 

public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,调用execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。

 

public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。

 

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

 

ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

posted @ 2018-03-19 20:57  1440min  阅读(229)  评论(0编辑  收藏  举报