线程--线程创建的几种方法及比较

25 篇文章 0 订阅

Java应用程序主程序

 应用程序运行时,运行环境调用应用程序的入口点(main()方法)时,将创建应用程序主线程。

public class ThreadDemo {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+ " start");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+ " end");
    }
}
//output:
main start
main end

创建和启动新线程

 主线程以外的线程一般称为工作线程。
 在java语言中,创建线程有4种方式:
1. 继承java.lang.Thread类;
2. 实现java.lang.Runnable 接口;
3. 实现Callable接口;
4. 通过匿名类创建;

1.继承java.lang.Thread 类:

创建一个Thread对象实例,即创建一个线程。
当调用Thread对象实例的start()方法时,将自动调用对象的run()方法(线程任务代码实现),即运行线程。如果对象的run()方法结束或运行过程抛出异常,则线程结束,且线程对象实例等待垃圾回收处理。

  • 实现:
具体步骤:
/**
         * 继承Thread类方式创建新线程
         *
         * 1.创建自定义的类继承Thread类,并且重写run方法
         * 2.实例化自定义类
         * 3.通过实例化对象调用start方法来创建新线程
         */
public class ThreadDemo01 extends Thread{
    //重写run()方法
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " subthread start");
        System.out.println(Thread.currentThread().getName() + " subthread end");
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        //继承Thread类
        System.out.println(Thread.currentThread().getName()+" start");
        ThreadDemo01 threadDemo01 = new ThreadDemo01();
        threadDemo01.start();//启动线程
        System.out.println(Thread.currentThread().getName()+" end");

    }
}

//output:
main start
main end
Thread-0 subthread start
Thread-0 subthread end
2.实现java.lang.Runnable 接口
  • 实现:
具体步骤:
/**
 * 实现Runnable接口
 * <p>
 * 1.创建自定义类并实现Runnable接口,并实现接口
 * 2.实例化自定义的类
 * 3.将自定义类的实例作为参数给Thread类,创建thread实例
 * 4.调用thread实例的start方法,启动子进程
 *
 * @param args
 */
public class Runnable01 implements  Runnable  {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+" subthread start");
        System.out.println(Thread.currentThread().getName()+" subthread end");
    };
}

public class ThreadDemo {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+" start");
        Runnable01 runnable01 = new Runnable01();
        Thread thread = new Thread(runnable01);
        thread.start();
        System.out.println(Thread.currentThread().getName()+" end");
    }
}
//output:
main start
main end
Thread-0 subthread start
Thread-0 subthread end
3.实现Callable接口
  • 实现:
具体步骤;
/**
         * 实现Callable接口
         *
         * Callable接口的实现是线程池提供的一种创建线程的方式
         * 1. 实现Callable接口,并且实现call方法
         * 2. 创建线程池(Executors工具类提供的方法创建线程池)
         * 3. 创建Callable接口实现类的实例
         * 4. 将实例对象通过线程池的submit方法提交给线程池从而创建新线程
         *
         */
public class Callable01 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println(Thread.currentThread().getName()+" subthread start");
        Integer i = 10;
        System.out.println(Thread.currentThread().getName()+" subthread end");
        return i;
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+" start");
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Callable01 callable01 = new Callable01();
        Future<Integer> future = executorService.submit(callable01);
        try {
            Integer integer = future.get();
            future.cancel(true);
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+" end");
    }
}
//output:
main start
pool-1-thread-1 subthread start
pool-1-thread-1 subthread end
10
main end

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

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

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

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

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args)  
    {  
        CallableThreadTest ctt = new CallableThreadTest();  
        FutureTask<Integer> ft = new FutureTask<>(ctt);  
        for(int i = 0;i < 100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
            if(i==20)  
            {  
                new Thread(ft,"有返回值的线程").start();  
            }  
        }  
        try  
        {  
            System.out.println("子线程的返回值:"+ft.get());  
        } catch (InterruptedException e)  
        {  
            e.printStackTrace();  
        } catch (ExecutionException e)  
        {  
            e.printStackTrace();  
        }  
  
    }
    @Override  
    public Integer call() throws Exception  
    {  
        int i = 0;  
        for(;i<100;i++)  
        {  
            System.out.println(Thread.currentThread().getName()+" "+i);  
        }  
        return i;  
    }  
}

4.通过匿名类创建

(1)在主线程(main()方法)中,使用一个实现Runnable接口的匿名派生类对象为参数,创建一个Thread对象实例。

Thread thread1 = new Thread(new Runnable (){//创建线程对象实例(使用匿名对象)
public void run(){
//线程要执行的逻辑操作
}
})

(2)调用创建的Thread实例的Start()方法,启动新线程。

thread1.start();
  • 实现:
public class ThreadDemo {
    public static void main(String[] args) {
        //匿名类创建新线程
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10 ; i++) {
                    System.out.print(" "+ (int)(Math.random()*10));//打印随机数
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread.start();
    }
}
//output:

 1 2 9 8 8 7 4 8 6 0
几种方法的比较
  • 实现Runnable接口:Runnable实现类的run()方法是线程的执行体,注意Runnable对象只是作为Thread对象的target,实际的线程对象仍然是Thread实例。如果两个线程共享同一个target,那么也就共享了该Runnable类的实例变量。没有返回值且都无法抛出异常。
  • 继承Thread类:已经继承了Thread,就不能再继承其他类了(Java是单继承),多个线程之间无法共享线程类的实例变量。没有返回值且都无法抛出异常。
  • 实现Callable接口:提供了一个call()方法作为线程执行体。有返回值且会抛出异常。
    和run()方法相比,call()方法有返回值,可以声明抛出异常。

Callable接口的实现类不可以作为Thread对象的target,所以Java 5提供了一个Future接口来代表call()方法的值。FutureTask类既实现了Future接口,又实现了Runnable接口,可以作为Thread对象的target。所以可以通过FutureTask来包装Callable对象。
总结:
Runnable接口更好一些。

1,因为实现Runnable接口可以避免Java单继承的局限性。
当一个类继承了Thread,就不可以在继承其他类了。
而当一个类实现了Runnable,它一样可以继承其他类。
比如 class Demo extends SuperDemo implements Runnable{}

2,更符合面向对象的设计。
run()方法的作用是用来封装线程要运行的代码。
那么run()方法所属的对象,就是线程任务对象。
Thread类的子类对象即使线程对象,又是线程任务对象。耦合性很强。
有了Runnable接口,可以将线程任务和线程进行解耦,提高了程序的扩展性。

所以建议使用Runnable接口的方式完成线程的创建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值