精华内容
下载资源
问答
  • 如何创建线程创建线程几种方法?怎么实现的?

    多线程有几种实现方法?

    多线程实现又3种方法,其中前两中是常用的方法,推荐第二种方法,一个类应该在其修改或者加强是才继承

    1.继承Thread类,重写run()方法,实例化该类,调用线程start()方法

    (1)自定义类,继承Thread类,重写run()方法

    (2)创建该Thread子类实例

    (3)然后调用线程start()方法


        public class TestThread extends  Thread{
            @Override
            public void run() {
                printThreadMsg("1.2.new TestThread run");
            }
        }
        /**
         * 打印线程信息
         * @param msg
         */
        private void printThreadMsg(String msg)
        {
            System.out.println(msg+":threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
        }

            /**
             * 1.1 匿名内部类(继承Thread类,重写run()方法)
             */
            new Thread(){
                @Override
                public void run() {
                    printThreadMsg("1.1 new Thread() run");
                }
            }.start();
            /**
             * 1.2 继承Thread类,重写run()方法
             */
            new TestThread().start();

    2.实现Runnable接口,并实现该接口的run()的方法,

    具体步骤:

    (1)自定义类,并实现Runnable接口,实现run()方法

    (2)创建Thread子类实例:用实现Runnable接口的对象作为参数实例化个Thread对象

    (3)然后调用线程start()方法

        public class TestRunnable implements  Runnable{
            @Override
            public void run() {
                printThreadMsg("2.2.TestRunnable run");
            }
        }
    

       /**
             * 2.1实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
             */
            new Thread(new TestRunnable()).start();
    
            /**
             * 2.2实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
             */
            new Thread(new Runnable() {
                @Override
                public void run() {
                    printThreadMsg("2.2. new Thread.new Runnable run");
                }
            }).start();



    3.实现Callable接口,重写call()方法

    (1)自定义类,实现Callable接口,实现call()方法

    (2)实例化ExecutorService 对象,实例化个刚刚自定义类(实现Callable接口)的对象,把它作为参数调用submit()方法

    (3)注意get()方法获取结果会造成阻塞

        public static  class   TestCallable implements Callable{
            @Override
            public Object call() throws Exception {
                /**
                 * 沉睡6秒,模拟耗时操作
                 */
                Thread.sleep(6000);
                System.out.println("3.TestCallable  call:threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
    
                return "这是 TestCallable call 执行完 返回的结果";
            }
        }

          /**
             *实现Callable接口,重写call()方法
             */
            ExecutorService mExecutorService= Executors.newSingleThreadExecutor();
            Future future=mExecutorService.submit(new TestCallable());
            try {
                /**
                 * future.get()用来获取结果,  会造成线程阻塞,直到call()结束
                 * 等待线程结束,并且返回结果
                 * 线程阻塞了
                 */
            String result= String.valueOf(future.get());
            System.out.println("3.TestCallable call return:"+result+","+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
    
            } catch (Exception e) {
                e.printStackTrace();
            }

    最后附上所有代码

    package com.hex168.demo.therad;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import java.lang.ref.WeakReference;
    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;
    
    /**
     * author:dz_hexiang on 2017/9/23 13:06
     * email:472482006@qq.com
     * 测试线程创建
     */
    public class ThreadActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_therad);
            /**
             * 1.1 匿名内部类(继承Thread类,重写run()方法)
             */
            new Thread(){
                @Override
                public void run() {
                    printThreadMsg("1.1 new Thread() run");
                }
            }.start();
            /**
             * 1.2 继承Thread类,重写run()方法
             */
            new TestThread().start();
    
            /**
             * 2.1实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
             */
            new Thread(new TestRunnable()).start();
    
            /**
             * 2.2实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
             */
            new Thread(new Runnable() {
                @Override
                public void run() {
                    printThreadMsg("2.2. new Thread.new Runnable run");
                }
            }).start();
    
    
            /**
             *实现Callable接口,重写call()方法
             */
            ExecutorService mExecutorService= Executors.newSingleThreadExecutor();
            Future future=mExecutorService.submit(new TestCallable());
            try {
                /**
                 * future.get()用来获取结果,  会造成线程阻塞,直到call()结束
                 * 等待线程结束,并且返回结果
                 * 线程阻塞了
                 */
            String result= String.valueOf(future.get());
            System.out.println("3.TestCallable call return:"+result+","+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            /**
             * handler 及runnable都是在主线程
             */
            handler.post(handlerRunnable);
        }
    
        public class TestThread extends  Thread{
            @Override
            public void run() {
                printThreadMsg("1.2.new TestThread run");
            }
        }
    
        public class TestRunnable implements  Runnable{
            @Override
            public void run() {
                printThreadMsg("2.2.TestRunnable run");
            }
        }
    
        public Runnable handlerRunnable =new Runnable() {
            @Override
            public void run() {
                printThreadMsg("4.handler handlerRunnable run");
            }
        };
    
        /**
         * 打印线程信息
         * @param msg
         */
        private void printThreadMsg(String msg)
        {
            System.out.println(msg+":threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
        }
    
        private MyHandler handler=new MyHandler(this);
        static class MyHandler extends Handler{
            WeakReference<Activity> activityWeakReference;
    
            MyHandler(Activity c)
            {
                activityWeakReference=new WeakReference<Activity>(c);
            }
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        }
    
        public static  class   TestCallable implements Callable{
            @Override
            public Object call() throws Exception {
                /**
                 * 沉睡6秒,模拟耗时操作
                 */
                Thread.sleep(6000);
                System.out.println("3.TestCallable  call:threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
    
                return "这是 TestCallable call 执行完 返回的结果";
            }
        }
    }
    

    运行结果



    展开全文
  • 创建线程几种方法及比较

    千次阅读 2016-11-21 10:17:24
    1、通过继承Thread类创建线程 (1).首先定义一个类去继承Thread父类,重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。 (2).直接创建一个ThreadTest类的对象,也可以利用多态性,变量声明为父类...

    1、通过继承Thread类创建线程

    (1).首先定义一个类去继承Thread父类,重写父类中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。
    (2).直接创建一个ThreadTest类的对象,也可以利用多态性,变量声明为父类的类型。

    (3).调用start方法,线程启动,隐含的调用run()方法。

    public class ThreadTest extends Thread{
    
    	public void run(){
    		for(int i=0;i<=10;i++){
    			System.out.println(i);
    		}		
    	}
    	
    	public static void main(String[] args) {
    		ThreadTest thread1=new ThreadTest();
    		ThreadTest thread2=new ThreadTest();
    		thread1.start();
    		thread2.start();
    	}
    }

    2、通过实现Runnable接口创建线程

    (1).定义一个类实现Runnable接口,重写接口中的run()方法。在run()方法中加入具体的任务代码或处理逻辑。

    (2).创建Runnable接口实现类的对象。

    (3).创建一个ThreadTest类的对象,需要封装前面Runnable接口实现类的对象。(接口可以实现多继承)

    (4).调用Thread对象的start()方法,启动线程

    public class ThreadTest implements Runnable{
    	
    	@Override
    	public void run() {
    		for(int i=0;i<=10;i++){
    			System.out.println(i);
    		}	
    	}
    	public static void main(String[] args) {
    		ThreadTest threadTest=new ThreadTest();
    		Thread theard=new Thread(threadTest);
    		theard.start();
    	}
    }

    3.通过Callable和Future创建线程

    (1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。

    (2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。

    (3)使用FutureTask对象作为Thread对象的target创建并启动新线程。

    (4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

    public class ThreadTest implements Callable<Integer>{
    
    	@Override
    	public Integer call() throws Exception {
    		int count =0;
    		for(int i=0;i<=10;i++){
    			count=count+i;
    		}
    		return count;	
    	}
    	public static void main(String[] args) throws InterruptedException, ExecutionException {
    		ThreadTest test=new ThreadTest();
    		FutureTask<Integer> thread = new FutureTask<>(test);
    		new Thread(thread,"有返回值的线程").start();  
    		System.out.println(thread.get());
    	}
    	
    }


             使用实现Runnable接口方式创建线程可以共享同一个目标对象(TreadDemo1 tt=new TreadDemo1();),实现了多个相同线程处理同一份资源。

    然后再看一段来自JDK的解释:

    The Runnable interface should be implemented by any class whose instances are intended to be executed by a thread. The class must define a method of no arguments calledrun.

    This interface is designed to provide a common protocol for objects that wish to execute code while they are active. For example,Runnable is implemented by classThread. Being active simply means that a thread has been started and has not yet been stopped.

    In addition, Runnable provides the means for a class to be active while not subclassingThread. A class that implementsRunnable can run without subclassingThread by instantiating aThread instance and passing itself in as the target. In most cases, theRunnable interface should be used if you are only planning to override therun() method and no otherThread methods. This is important because classes should not be subclassed unless the programmer intends on modifying or enhancing the fundamental behavior of the class.

    采用实现Runnable、Callable接口的方式创见多线程时,优势是:

    线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。

    在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

    劣势是:

    编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。

    采用继承Thread类方式:
    (1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。
    (2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。
    采用实现Runnable接口方式:
    (1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
    (2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。






    展开全文
  • 创建线程几种方法

    千次阅读 2017-11-29 22:23:00
    创建线程几种方式) 多线程有三种实现方法: 1、继承Thread类,重写run()方法。然后直接new这个对象的实例,创建一个线程的实例,再调用start()方法启动线程。(其实本质上Thread是实现了...

    多线程有几种实现方法,分别是什么?(创建线程的几种方式)


    多线程有三种实现方法:

    1、继承Thread类,重写run()方法。然后直接new这个对象的实例,创建一个线程的实例,再调用start()方法启动线程。(其实本质上Thread是实现了Runnable接口的一个实例,Thread源文件:public class Thread implements Runnable

    2、实现Runnable接口,重写run()方法。然后调用new Thread(runnable)的方式创建一个线程,再调用start()方法启动线程。

    3、实现Callable接口,重写call()方法。Callable是类似于Runnable的接口,是属于Executor框架中的功能类。是JDK1.5中引入的新特性。(不常用,作为了解引自于

    • Runnable和Callable的不同点:
    •         ①Callable规定的方法是call(),而Runnable规定的方法是run(). 
    •         ②Callable的任务执行后可返回值,而Runnable的任务是不能返回值的(有返回值用callable方法,无返回值用runnable方法
    •         ③call()方法可抛出异常,而run()方法是不能抛出异常的。 
    •         ④运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。它提供了检查计算是否完成的方法,以等
    •         待计算的完成,并检索计算的结果.通过Future对象可了解任务执行情况,可取消任务的执行,还可获取任务执行的结果

    前两种方法的详细分析:

    (1)继承Thread类,重写run()方法:

    1、定义一个类继承Thread类。

    2、覆盖Thread类中的run方法。


    3、创建一个线程的实例(Thread类的子类对象)。


    4、调用start方法启动线程执行run方法。



    (2)实现Runnable接口,重写run()方法:

    1、定义类实现Runnable接口。


    2、重写接口中的run()方法,将线程的任务代码封装到run()方法中。



    3、通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。

    为什么要进行参数传递?因为线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就明确要运行的任务。


    4、调用线程对象的start方法开启线程。


    实现Runnable接口的好处,优点:

    1、实现Runnable接口的方法中线程类只是实现了Runnable接口,还可以继承其他的类。避免的java单继承的局限性。

    2、在这种方式下,可以多个线程共享一个Runnable对象,利于资源共享。适合多个相同的线程去处理同一份资源。

    尽量使用实现Runnable接口的方法

    展开全文
  • 线程创建的四方式

    万次阅读 多人点赞 2018-03-30 14:34:14
    java中创建线程的四种方法以及区别 Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线程...

    java中创建线程的四种方法以及区别

    Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示:

    1)继承Thread类创建线程

    2)实现Runnable接口创建线程

    3)使用Callable和Future创建线程

    4)使用线程池例如用Executor框架

    下面让我们分别来看看这四种创建线程的方法。

    ------------------------继承Thread类创建线程---------------------

    通过继承Thread类来创建并启动多线程的一般步骤如下

    1】d定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。

    2】创建Thread子类的实例,也就是创建了线程对象

    3】启动线程,即调用线程的start()方法

    代码实例

    public class MyThread extends Thread{//继承Thread类

      public void run(){

      //重写run方法

      }

    }

    public class Main {

      public static void main(String[] args){

        new MyThread().start();//创建并启动线程

      }

    }

    ------------------------实现Runnable接口创建线程---------------------

    通过实现Runnable接口创建并启动线程一般步骤如下:

    1】定义Runnable接口的实现类,一样要重写run()方法,这个run()方法和Thread中的run()方法一样是线程的执行体

    2】创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象

    3】第三部依然是通过调用线程对象的start()方法来启动线程

    代码实例:

    public class MyThread2 implements Runnable {//实现Runnable接口

      public void run(){

      //重写run方法

      }

    }

    public class Main {

      public static void main(String[] args){

        //创建并启动线程

        MyThread2 myThread=new MyThread2();

        Thread thread=new Thread(myThread);

        thread().start();

        //或者    new Thread(new MyThread2()).start();

      }

    }

    ------------------------使用Callable和Future创建线程---------------------

    和Runnable接口不一样,Callable接口提供了一个call()方法作为线程执行体,call()方法比run()方法功能要强大。

    》call()方法可以有返回值

    》call()方法可以声明抛出异常

    Java5提供了Future接口来代表Callable接口里call()方法的返回值,并且为Future接口提供了一个实现类FutureTask,这个实现类既实现了Future接口,还实现了Runnable接口,因此可以作为Thread类的target。在Future接口里定义了几个公共方法来控制它关联的Callable任务。

    >boolean cancel(boolean mayInterruptIfRunning):视图取消该Future里面关联的Callable任务

    >V get():返回Callable里call()方法的返回值,调用这个方法会导致程序阻塞,必须等到子线程结束后才会得到返回值

    >V get(long timeout,TimeUnit unit):返回Callable里call()方法的返回值,最多阻塞timeout时间,经过指定时间没有返回抛出TimeoutException

    >boolean isDone():若Callable任务完成,返回True

    >boolean isCancelled():如果在Callable任务正常完成前被取消,返回True

    介绍了相关的概念之后,创建并启动有返回值的线程的步骤如下:

    1】创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象)。

    2】使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值

    3】使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)

    4】调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

    代码实例:

    public static class MyThread3 implements Callable{
    
        @Override
        public Object call() throws Exception {
            return 5;
        }
    }

    public class Main {

      public static void main(String[] args){

       MyThread3 th=new MyThread3();

       //也可以直接使用Lambda表达式创建Callable对象

         //使用FutureTask类来包装Callable对象

       FutureTask<Integer> future=new FutureTask<Integer>(

        (Callable<Integer>)()->{

          return 5;

        }

        );

       new Thread(future,"有返回值的线程").start();//实质上还是以Callable对象来创建并启动线程

        try{

        System.out.println("子线程的返回值:"+future.get());//get()方法会阻塞,直到子线程执行结束才返回

        }catch(Exception e){

        ex.printStackTrace();

       }

      }

    }

    ------------------------使用线程池例如用Executor框架---------------------

    1.5后引入的Executor框架的最大优点是把任务的提交和执行解耦。要执行任务的人只需把Task描述清楚,然后提交即可。这个Task是怎么被执行的,被谁执行的,什么时候执行的,提交的人就不用关心了。具体点讲,提交一个Callable对象给ExecutorService(如最常用的线程池ThreadPoolExecutor),将得到一个Future对象,调用Future对象的get方法等待执行结果就好了。Executor框架的内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象。

        Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。

        Executor接口中之定义了一个方法execute(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类。ExecutorService接口继承自Executor接口,它提供了更丰富的实现多线程的方法,比如,ExecutorService提供了关闭自己的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以调用ExecutorService的shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。因此我们一般用该接口来实现和管理多线程。

        ExecutorService的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了的任务,当素有已经提交了的任务执行完后,便到达终止状态。如果不调用shutdown()方法,ExecutorService会一直处在运行状态,不断接收新的任务,执行新的任务,服务器端一般不需要关闭它,保持一直运行即可。

        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类。

        这四种方法都是用的Executors中的ThreadFactory建立的线程,下面就以上四个方法做个比较




    newCachedThreadPool()                                                                                                                                         

    -缓存型池子,先查看池中有没有以前建立的线程,如果有,就 reuse.如果没有,就建一个新的线程加入池中
    -缓存型池子通常用于执行一些生存期很短的异步型任务
     因此在一些面向连接的daemon型SERVER中用得不多。但对于生存期短的异步任务,它是Executor的首选。
    -能reuse的线程,必须是timeout IDLE内的池中线程,缺省     timeout是60s,超过这个IDLE时长,线程实例将被终止及移出池。
      注意,放入CachedThreadPool的线程不必担心其结束,超过TIMEOUT不活动,其会自动被终止。
     


    newFixedThreadPool(int)                                                      

    -newFixedThreadPool与cacheThreadPool差不多,也是能reuse就用,但不能随时建新的线程
    -其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外的队列中等待直到当前的线程中某个线程终止直接被移出池子
    -和cacheThreadPool不同,FixedThreadPool没有IDLE机制(可能也有,但既然文档没提,肯定非常长,类似依赖上层的TCP或UDP IDLE机制之类的),所以FixedThreadPool多数针对一些很稳定很固定的正规并发线程,多用于服务器
    -从方法的源代码看,cache池和fixed 池调用的是同一个底层 池,只不过参数不同:
    fixed池线程数固定,并且是0秒IDLE(无IDLE)    
    cache池线程数支持0-Integer.MAX_VALUE(显然完全没考虑主机的资源承受能力),60秒IDLE  

     
    newScheduledThreadPool(int)
    -调度型线程池
    -这个池子里的线程可以按schedule依次delay执行,或周期执行
     
    newSingleThreadExecutor()
    -单例线程,任意时间池中只能有一个线程
    -用的是和cache池和fixed池相同的底层池,但线程数目是1-1,0秒IDLE(无IDLE)

     

        一般来说,CachedTheadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的Executor的首选,只有当这种方式会引发问题时(比如需要大量长时间面向连接的线程时),才需要考虑用FixedThreadPool。(该段话摘自《Thinking in Java》第四版)

                             

    Executor执行Runnable任务

        通过Executors的以上四个静态工厂方法获得 ExecutorService实例,而后调用该实例的execute(Runnable command)方法即可。一旦Runnable任务传递到execute()方法,该方法便会自动在一个线程上

    [java] view pl
     
    import java.util.concurrent.ExecutorService;   
    import java.util.concurrent.Executors;   
      
    public class TestCachedThreadPool{   
        public static void main(String[] args){   
            ExecutorService executorService = Executors.newCachedThreadPool();   
    //      ExecutorService executorService = Executors.newFixedThreadPool(5);  
    //      ExecutorService executorService = Executors.newSingleThreadExecutor();  
            for (int i = 0; i < 5; i++){   
                executorService.execute(new TestRunnable());   
                System.out.println("************* a" + i + " *************");   
            }   
            executorService.shutdown();   
        }   
    }   
      
    class TestRunnable implements Runnable{   
        public void run(){   
            System.out.println(Thread.currentThread().getName() + "线程被调用了。");   
        }   
    }  

       某次执行后的结果如下:

       从结果中可以看出,pool-1-thread-1和pool-1-thread-2均被调用了两次,这是随机的,execute会首先在线程池中选择一个已有空闲线程来执行任务,如果线程池中没有空闲线程,它便会创建一个新的线程来执行任务。

    Executor执行Callable任务

        在Java 5之后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。并且Callable的call()方法只能通过ExecutorService的submit(Callable<T> task) 方法来执行,并且返回一个 <T>Future<T>,是表示任务等待完成的 Future。

        Callable接口类似于Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常而Callable又返回结果,而且当获取返回结果时可能会抛出异常。Callable中的call()方法类似Runnable的run()方法,区别同样是有返回值,后者没有。

        当将一个Callable的对象传递给ExecutorService的submit方法,则该call方法自动在一个线程上执行,并且会返回执行结果Future对象。同样,将Runnable的对象传递给ExecutorService的submit方法,则该run方法自动在一个线程上执行,并且会返回执行结果Future对象,但是在该Future对象上调用get方法,将返回null。

        下面给出一个Executor执行Callable任务的示例代码:

    import java.util.ArrayList;   
    import java.util.List;   
    import java.util.concurrent.*;   
      
    public class CallableDemo{   
        public static void main(String[] args){   
            ExecutorService executorService = Executors.newCachedThreadPool();   
            List<Future<String>> resultList = new ArrayList<Future<String>>();   
      
            //创建10个任务并执行   
            for (int i = 0; i < 10; i++){   
                //使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中   
                Future<String> future = executorService.submit(new TaskWithResult(i));   
                //将任务执行结果存储到List中   
                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();   
                    }   
            }   
        }   
    }   
      
      
    class TaskWithResult implements Callable<String>{   
        private int id;   
      
        public TaskWithResult(int id){   
            this.id = id;   
        }   
      
        /**  
         * 任务的具体过程,一旦任务传给ExecutorService的submit方法, 
         * 则该方法自动在一个线程上执行 
         */   
        public String call() throws Exception {  
            System.out.println("call()方法被自动调用!!!    " + Thread.currentThread().getName());   
            //该返回结果将被Future的get方法得到  
            return "call()方法被自动调用,任务返回的结果是:" + id + "    " + Thread.currentThread().getName();   
        }   
    }  

        某次执行结果如下:

       

        从结果中可以同样可以看出,submit也是首先选择空闲线程来执行任务,如果没有,才会创建新的线程来执行任务。另外,需要注意:如果Future的返回尚未完成,则get()方法会阻塞等待,直到Future完成返回,可以通过调用isDone()方法判断Future是否完成了返回。

    自定义线程池

        自定义线程池,可以用ThreadPoolExecutor类创建,它有多个构造方法来创建线程池,用该类很容易实现自定义的线程池,这里先贴上示例程序:

    import java.util.concurrent.ArrayBlockingQueue;   
    import java.util.concurrent.BlockingQueue;   
    import java.util.concurrent.ThreadPoolExecutor;   
    import java.util.concurrent.TimeUnit;   
      
    public class ThreadPoolTest{   
        public static void main(String[] args){   
            //创建等待队列   
            BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);   
            //创建线程池,池中保存的线程数为3,允许的最大线程数为5  
            ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50,TimeUnit.MILLISECONDS,bqueue);   
            //创建七个任务   
            Runnable t1 = new MyThread();   
            Runnable t2 = new MyThread();   
            Runnable t3 = new MyThread();   
            Runnable t4 = new MyThread();   
            Runnable t5 = new MyThread();   
            Runnable t6 = new MyThread();   
            Runnable t7 = new MyThread();   
            //每个任务会在一个线程上执行  
            pool.execute(t1);   
            pool.execute(t2);   
            pool.execute(t3);   
            pool.execute(t4);   
            pool.execute(t5);   
            pool.execute(t6);   
            pool.execute(t7);   
            //关闭线程池   
            pool.shutdown();   
        }   
    }   
      
    class MyThread implements Runnable{   
        @Override   
        public void run(){   
            System.out.println(Thread.currentThread().getName() + "正在执行。。。");   
            try{   
                Thread.sleep(100);   
            }catch(InterruptedException e){   
                e.printStackTrace();   
            }   
        }   
    }  

      运行结果如下:

        从结果中可以看出,七个任务是在线程池的三个线程上执行的。这里简要说明下用到的ThreadPoolExecuror类的构造方法中各个参数的含义。   

    public ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long         keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue)

    corePoolSize:线程池中所保存的线程数,包括空闲线程。

    maximumPoolSize:池中允许的最大线程数。

    keepAliveTime:当线程数大于核心数时,该参数为所有的任务终止前,多余的空闲线程等待新任务的最长时间。

    unit:等待时间的单位。

    workQueue:任务执行前保存任务的队列,仅保存由execute方法提交的Runnable任务。

    --------------------------------------四种创建线程方法对比--------------------------------------

    实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值,后者线程执行体run()方法无返回值,因此可以把这两种方式归为一种这种方式与继承Thread类的方法之间的差别如下:

    1、线程只是实现Runnable或实现Callable接口,还可以继承其他类。

    2、这种方式下,多个线程可以共享一个target对象,非常适合多线程处理同一份资源的情形。

    3、但是编程稍微复杂,如果需要访问当前线程,必须调用Thread.currentThread()方法。

    4、继承Thread类的线程类不能再继承其他父类(Java单继承决定)。

    5、前三种的线程如果创建关闭频繁会消耗系统资源影响性能,而使用线程池可以不用线程的时候放回线程池,用的时候再从线程池取,项目开发中主要使用线程池

    注:在前三种中一般推荐采用实现接口的方式来创建多线程

    创建线程本质只有1种,即创建Thread类,以上的所谓创建方式其实是实现run方法的方式:

    实现run方法的方式分为两类,你所看到的其他的都是对这两类的封装:

    1、实现runnable接口的run方法,并把runnable实例作为target对象,传给thread类,最终调用target.run

    2、继承Thread类,重写Thread的run方法,Thread.start会执行run方法

    展开全文
  • Qt创建线程几种方法

    千次阅读 2017-01-04 10:39:45
    一、继承QThread 继承QThread,这应该是最常用的方法...这种方法,我们每一次要新建一个线程都需要继承Qthread,实现一个新的类,有点不太方便。但是相对于Qrunnable,这种方法的好处就是我们可以直接调用对象的sta
  • C#创建线程几种方法

    千次阅读 2018-05-28 16:28:14
    https://blog.csdn.net/lengsexizuo/article/details/38728473
  • 用Python创建线程几种方法

    千次阅读 2019-06-01 16:40:48
    经过总结,Python创建线程主要有如下两种方法: 函数 类 接下来,我们就来揭开多线程的神秘面纱。 学会使用函数创建线程 在Python3中,Python提供了一个内置模块threading.Thread,可以很方便地让我们创建...
  • 创建线程几种方式
  • 线程作为Java中很重要的一个知识点,在此还是有必要总结一下的。 一.线程的生命周期及五基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: ...新建状态(New):当线程对象对创建后,即进入
  • C++11 std::thread创建线程几种写法

    万次阅读 2020-12-06 14:00:10
    本文主要介绍标准C++中 thread的创建线程几种方式。 使用时需要加头文件:#include <thread> 位于std命名空间中,是跨平台的线程操作。 2 使用说明 1、通过函数指针创建 一般来说,像linux下pthread_create...
  • 创建并启动线程几种方式

    千次阅读 2017-12-14 23:26:12
    一:创建线程几种方式 1.第一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法,然后在run方法里填写相应的逻辑代码。class ThreadDemo1 extends Thread{ @Override public void run() {...
  • 这是最新的大厂面试系列,还原真实场景,提炼出知识点分享给大家。 点赞再看,养成习惯~ 微信搜索【武哥聊编程】,关注这个 Java 菜鸟。...Java 创建线程有两方式: 继承Thread类,并重写run(...
  • 创建线程几种方式

    千次阅读 2018-08-27 15:48:35
    一般有四种方法,Thread,Runnable,Callable,使用Executor框架来创建线程池。 Runnable和Callable的区别是, (1)Callable规定的方法是call(),Runnable规定的方法是run(). (2)Callable的任务执行后可返回值,而...
  • 二、创建线程几种方式

    千次阅读 2016-10-19 20:45:40
    一、使用Thread创建线并启动线程java.lang.Thread类是线程类,其每一个实例表示一个可以并发运行的线程。我们可以通过继承该类并重写run方法来定义一个具体的线程。其中重写run方法的目的是定义该线程要执行的逻辑。...
  • android 创建线程几种方法

    万次阅读 2014-06-16 23:48:45
    为什么Java要提供两种方法创建线程呢?它们都有哪些区别?相比而言,哪一种方法更好呢?   在Java中,类仅支持单继承,也就是说,当定义一个新的类的时候,它只能扩展一个外部类.这样,如果创建自定义线程...
  • 详解Java创建线程几种方式

    千次阅读 2017-10-19 20:14:30
    在Java线程中,有以下三方式可以实现线程创建。 通过继承Thread类,调用Thread的start方法实现线程创建 实现Runnable接口 实现Callable接口 继承Thread可以实现线程创建,但当我们需要继承其他父类的时候...
  • 创建线程的四方式

    千次阅读 多人点赞 2019-10-03 21:55:47
    创建线程的四方式 继承Thread类 实现Runnable接口 使用Callable和Future创建线程 使用Executor框架创建线程池 继承Thread类 步骤 定义一个Thread类的子类,重写run方法,将相关逻辑实现,run()方法就是线程要...
  • std::thread 创建线程几种方式

    千次阅读 2019-04-18 08:22:54
    本文主要介绍标准C++中 thread的创建线程几种方式。 使用时需要加头文件: #include <thread> 位于std命名空间中,是跨平台的线程操作 使用说明 1、通过函数指针创建 一般来说,像CreateThread、_...
  • 首先,我们大家都知道,创建线程的两蛀主要的方法,一是继承Thread类,另一是实现Runnable接口。对于第一种创建线程的方式有两个不足:1.当前线程重写run方法定义该线程要完成的工作,这就导致了任务是定义在...
  • c++多线程创建几种方式

    千次阅读 2017-05-23 12:11:27
    c++创建线程几种方法(入门)
  • java 创建线程的三方式、创建线程池的四方式

    万次阅读 多人点赞 2019-02-23 21:01:44
    java创建线程的三方式: 继承Thread类创建线程类 实现Runnable接口 通过Callable和Future创建线程 java创建线程池的四方式: newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理...
  • Qt创建线程的两种方法

    万次阅读 多人点赞 2017-12-25 15:33:54
    1.摘要 Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方...两种方法区别不大...
  • 线程常用的创建方式,有两,第一是使用Runnable。第二是继承Thread类型。 实现Runnable接口更好一些。 1,因为实现Runnable接口可以避免Java单继承的局限性。 当一个类继承了Thread,就不可以在继承其他类了...
  • 创建线程几种不同的方式?

    千次阅读 2017-04-20 10:45:26
    ①继承Thread类(真正意义上的线程类),是Runnable接口的实现。 ②实现Runnable接口,并重写里面的run方法。...继承于Thread类的线程类,可以直接调用start方法启动线程(使用static也可以实现资源共享).一个
  • 创建线程的三种方法

    千次阅读 2012-05-11 20:59:47
    MFC中有两类线程,分别称之为工作者线程和用户界面线程。二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环。...但对于Win32的API编程而言,这两种线程是没有区别的,它们都
  • java创建线程的三方式: 继承Thread类创建线程类 通过Runable接口创建线程类 通过Callable和FutureTask创建线程 总结下: 实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值。 1...
  • Java 创建线程的三方式总结

    万次阅读 2020-12-03 11:13:19
    那么创建线程几种方式呢? 1、继承 Thread 类 直接继承 Thread 即可实现多线程。Thread 本质上也是实现了 Runnable 接口,线程启动的唯一方法是通过 Thread 类的 start() 实例方法实现的。start() 方法调用时,...
  • 创建线程有哪几种方式?3种

    千次阅读 2020-07-20 08:17:10
    1.继承Thread类型重写run 方法 public class ThreadDemoTest extends Thread{ @Override public void run() { System.out.println("通过继承Thread类重写run方法实现接口!"); } public static void main...
  • c++11多线程编程(一):创建线程的三种方法

    万次阅读 多人点赞 2017-11-03 14:45:08
    c++11线程库 原始的c++标准仅支持单线程编程,新的c++标准(c++11或c++0x)于2011年发布,引入了新的线程库。 编译器要求: Linux: gcc 4.8.1 (完全并发...在linux下的编译方法:g++ -std=c++11 sample.cpp -lpthread

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 558,717
精华内容 223,486
关键字:

创建线程的几种方法