线程的创建+创建线程常见的三种方式

Java中创建线程主要有三种方式:

一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。Thread类实际上就是实现了Runnable接口。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
优缺点:
       缺点:1、继承父类,类只能单继承
                  2、不可以实现资源的共享
代码:

public class Rabbit1 extends Thread{
    int i=0;
    //重写run方法
    @Override
    public void run() {
        super.run();
        for (i=0;i<10;i++){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName()+i+":"+"开始运行!");
        }
    }

    public static void main(String[] args) {
        //实例化线程类
        Rabbit1 r = new Rabbit1();
        //启动线程
        r.start();
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //输出主线程信息
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

运行效果:

main:0
Thread-00:开始运行!
main:1
Thread-01:开始运行!
main:2
Thread-02:开始运行!
main:3
Thread-03:开始运行!
main:4
Thread-04:开始运行!
main:5
Thread-05:开始运行!
main:6
Thread-06:开始运行!
main:7
Thread-07:开始运行!
main:8
Thread-08:开始运行!
Thread-09:开始运行!
main:9

二、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
优缺点:
       优点:1、类只能单继承,而接口可以多实现
                  2、可以实现资源的共享
代码示例,模拟抢票:

public class TicketTest {
    public static void main(String[] args) {
        //票就实例化一次,同20张票
        Ticket ti = new Ticket();
        //三个窗口同时售票
        Thread t1 = new Thread(ti,"窗口一:");
        Thread t2 = new Thread(ti,"窗口二:");
        Thread t3 = new Thread(ti,"窗口三:");
        t1.start();
        t2.start();
        t3.start();
    }
}
//实现Runnable方法
class Ticket implements Runnable{
    //共享的资源
    int tickets =20;

    @Override
    public void run() {
        while (true){
            //关键字控制线程安全
            synchronized (this){
                if (tickets<=0){
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"正在卖第  "+tickets+"  张票!");
                tickets--;
            }
        }

    }
}

运行效果:

窗口一:正在卖第  20  张票!
窗口一:正在卖第  19  张票!
窗口一:正在卖第  18  张票!
窗口一:正在卖第  17  张票!
窗口一:正在卖第  16  张票!
窗口一:正在卖第  15  张票!
窗口一:正在卖第  14  张票!
窗口一:正在卖第  13  张票!
窗口一:正在卖第  12  张票!
窗口三:正在卖第  11  张票!
窗口二:正在卖第  10  张票!
窗口三:正在卖第  9  张票!
窗口一:正在卖第  8  张票!
窗口一:正在卖第  7  张票!
窗口三:正在卖第  6  张票!
窗口二:正在卖第  5  张票!
窗口二:正在卖第  4  张票!
窗口二:正在卖第  3  张票!
窗口二:正在卖第  2  张票!
窗口二:正在卖第  1  张票!

三、通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
代码:

//有返回值的线程,实现Callable接口
public class RandomCallable implements Callable<Integer> {
    public static void main(String[] args) throws Exception{
        //创建callAble对象
        Callable callable = new day0514.thread.create2.RandomCallable();
        //新建FutureTask对象
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        //新建线程对象
        Thread t1 = new Thread(futureTask,"产生随机数");
        //启动线程
        t1.start();
        //判断线程是否运行完毕
        System.out.println(futureTask.isDone());
        //如何获取call()方法的返回值
        // Integer num = futureTask.get();//线程阻塞 不拿到结果我就不走了
        // get(等待的时间 , TimeUnit.SECONDS) 如果超时 就报错 TimeoutException
        Integer result = futureTask.get(3, TimeUnit.SECONDS);
        //判断线程是否运行完毕
        System.out.println(futureTask.isDone());
        System.out.println(result);
    }
/*
产生随机数的多线程
1.可以有返回值  可以根据泛型 自定义
2.call()此方法  抛出了一个最大的异常
*/
    @Override
    public Integer call() throws Exception {

        int random = (int)(Math.random()*10);
        Thread.sleep(2000);
        return random;
    }
}

运行效果

false//此处运行后停顿两秒
true
7

四、创建线程的三种方式的对比

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值