关于多线程的创建,及区别

创建线程有三种方式

1.继承Thread

2.实现Runnable接口

3.实现Callable接口

.继承Thread,重写run方法,用start启动,(调用start()方法与run()方法的区别:调用run不会起新的线程,调用start会启用新的线程)

/**
 * 线程任务类
 * 创建线程的三种方法一
 * 继承Thread类,重写run方法,用start启动
 */
public class testThreadOne extends Thread{
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println("线程名称:"+this.getName()+";任务"+i);
        }
    }


    public static void main(String[] args) {
        //第一种方法:继承Thread类重写run方法,用start启动线程
        //1.调用run方法,不会起新的线程;
        //2.调用start方法,会起新的线程;
        testThreadOne testThread = new testThreadOne();
        testThreadOne testThread1 = new testThreadOne();
        testThread.start();
        testThread1.run();
    }
}

二.实现Runnable接口,重写run方法,用start方法启动

/**
 * 线程任务类
 * 创建线程三种方法二
 * 实现Runnable接口来创建线程
 * 1.实现Runnable接口,并重写run方法
 * 2.创建一个任务类的对象
 * 3.任务类必须在线程中执行,因此将任务类的对象作为参数,创建一个Thread类对象,该Thread类对象才是真正的线程对象
 * 4.用start起订线程
 * 注:
 *  变量隔离
 *  锁
 *
 */
public class testThreadTwo implements Runnable{
    public static void main(String[] args) {

        testThreadTwo testThreadTwo = new testThreadTwo();
        testThreadTwo testThreadTwo1 = new testThreadTwo();
        Thread t1 = new Thread(testThreadTwo);
        Thread t2 = new Thread(testThreadTwo1);
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        for (int i = 0; i <20; i++) {
            System.out.println("线程名称:"+Thread.currentThread().getName()+";任务"+i);
        }
    }





}

三.实现Callbale接口重写call方法,且利用FutureTask

/**
 * 线程任务类
 * 创建线程三种方法三
 * 1.创建一个任务类,实现Callable接口,并实现call()方法,call()方法中的内容就是需要线程完成任务,且有返回值
 * 2,创建一个任务类的对象,并使用FutureTask类来包装任务类的对象,该FutureTask对象封装了任务类对象中call()方法的返回值
 * 3.任务类必须在线程中执行,因此将FutureTask类的对象作为参数,创建一个Thread类对象,该Thread类对象才是整整的线程对象
 * 4,调用Thread线程类对象的start()方法,来起订一个线程。
 * 5,调用FutureTask类对象的get()方法来获取线程执行的返回值,即人物类对象call()方法的返回值
 */
public class testThreadThree    implements  Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (i = 0; i < 20; i++) {
            if (i == 5)
                break;
            System.out.println(Thread.currentThread().getName() + "--- " + i);
        }
        return i;
    }

    public static void main(String[] args) {
        testThreadThree tt = new testThreadThree();
        FutureTask<Integer> ft = new FutureTask<>(tt);
        Thread thread = new Thread(ft);
        thread.start();
        try {
            System.out.println(Thread.currentThread().getName() + " main方法里面的参数 " + ft.get());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

三种方法比较:

1.继承Thread类的方法:

优点:编写容易,任务类中访问当前线程可以使用this关键字

缺点:任务类即线程类已经继承了Thread类,所以不能再继承其他父类

2.实现Runnable接口的方式:

优点:任务类只实现了Runnable接口,还可以继承其他类,可以多个线程对象共享一个任务类对象,即多线程共享一份资源的情况下

缺点:编写稍微复杂,任务类中访问当前线程,必须使用Thread.currentThread()方法

3.实现Callable和Future的方式

优点:任务类只是实现了Callable接口,还可以继承其他类,同样多线程下可以共享一份资源,这种方式还有返回值,并且可以抛出返回值的异常

缺点:编写复杂,任务类中访问当前线程时,必须使用Thread.currentThread()方法

总结:

仅仅只重写run()方法,而不是重写Thread类其他方法的前提下,比较推荐实现Runnable接口的方式创建线程

因为不仅修改或者增强类的能力,不应该为其创建子类,而且实现Runnable接口的方式,线程和资源相对分离,程序更加健壮,更符合面向对象的变成思想,当然,需要线程有返回值时可以使用Callable的方式,但Callable的方式有一个问题,当调用get()方法时,如果线程还未执行完毕则会阻塞到线程执行完毕拿到返回值

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值