多线程之线程创建

多线程之线程创建

一 ,线程创建

1.创建方式一

Java为开发者提供了一个类叫做Thread,此类的对象用来表示线程。创建线程并执行线程的步骤如下:

1.定义一个子类继承Thread2.再重写父类的run方法
3.创建Thread的子类对象
4.调用start方法启动线程(启动线程后,会自动执行run方法中的代码)

代码如下:

//1.定义一个子类继承thread类
public class MyThread extends Thread{

    //2.重写父类的run方法
    @Override
    public void run() {
        //描述线程的执行任务
        for (int i = 1; i <= 5; i++) {
            System.out.println("子线程MyThread输出" + i);
        }
    }
    
 //再定义一个测试类   
 public class ThreadTest1 {
     // main方法是由一条默认的主线程负责执行。
    public static void main(String[] args) {
        //3.创建MyThread的对象代表一个线程
        Thread t = new MyThread();
        //4.启动线程(自动调用run方法)
        t.start();
        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程Thread输出:" + i);
        }
    }
}

打印结果如下:

在这里插入图片描述

注意事项:

1.主线程和子线程是在抢占CPU的执行权,每次打印结果都会有所不同,因为主线程和子线程谁先执行是我们无法控制的。

2.启用线程必须是调用start方法而不是调用run方法,因为直接调用run方法会当成普通方法执行,此时还是相当于单线程执行,只有调用start方法才是启动一个新的线程执行。

此图为调用run方法的执行结果此图为调用run方法的执行结果

3.不要把主线程任务放在子线程任务之前,若是这样主线程一直是先跑完的,也相当于单线程的执行效果。

此图为主线程任务放在子线程任务之前的执行结果此图为主线程任务放在子线程任务之前的执行结果

创建方式一的优缺点:

1.优点:编码便捷

2.缺点:线程类已经继承Thread,无法再继承其他的类了,不利于功能的扩展。

2.创建方式二

Java为开发者提供了一个Runnable接口,该接口中只有一个run方法,意思就是通过Runnable接口的实现类对象专门来表示线程要执行的任务。具体步骤如下:

1.定义一个线程任务类MyRunnable实现Runnable接口,
2.重写run方法(这里面就是线程要执行的代码)
2.再创建一个Runnable任务对象
3.MyRunnable任务对象交给Thread处理
4.调用Thread对象的start()方法启动线程(启动后会自动执行Runnable里面的run方法)

代码如下:

//1.定义一个任务类实现Runnable接口
public class MyRunnable implements Runnable{
    //2.重写Runnable接口的run方法
    @Override
    public void run() {
        //线程要执行的任务
        for (int i = 1; i <= 5; i++) {
            System.out.println("子线程输出===》" + i);
        }
    }
}
//再定义一个测试类
public class ThreadTest2 {
    public static void main(String[] args) {
        //3.创建任务类的对象
        Runnable target = new MyRunnable();
        //4.把任务对象交给线程对象处理,然后再启动线程
        // public Thread(Runnable target),因为有构造方法,可以直接传递target
        new Thread(target).start();

        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程输出===》" + i);
        }
    }

打印结果如下:

在这里插入图片描述

创建方式二的优缺点:

1.优点:线程任务类实现了接口,便于功能的扩展。

2.缺点:如果线程有执行结果是不能直接返回的。

3.创建方式二改进—匿名内部类

可以直接创建Runnable接口的匿名内部类对象,传递给Thread对象。

代码如下:

public class ThreadTest3 {
    public static void main(String[] args) {
        //直接创建 Runnable接口的匿名内部类形式(任务对象)
        Runnable target = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("子线程1输出===》" + i);
                }
            }
        };
        new Thread(target).start();

        //简化形式1
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("子线程2输出===》" + i);
                }
            }
        }).start();

        //简化形式2,因为Runnable接口是函数式接口,故可用lambda表达式简化
        new Thread(()-> {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("子线程3输出===》" + i);
                }

        }).start();

        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程main输出===》" + i);
        }
    }
}

打印结果如下:

在这里插入图片描述

4.创建方式三

​ 前面两种线程创建方式虽然简单便捷,但都有一种局限性,就是线程执行执行完毕后如果有数据需要返回,前面两种方式都返回不了,因为重写的run方法是无返回值类型。所以Java在JDK5中提供了Callable接口和FutureTask类来创建线程,它最大的优点就是有返回值。在Callable接口中有一个call方法,重写call方法就是线程要执行的代码,它是有返回值的。步骤如下:

1、创建任务对象
	定义一个类实现Callable接口,重写call方法,封装要做的事情,和要返回的数据。
	把Callable类型的对象封装成FutureTask(线程任务对象)。
2、把线程任务对象交给Thread对象。
3、调用Thread对象的start方法启动线程。
4、线程执行完毕后、通过FutureTask对象的的get方法去获取线程任务执行的结果。

代码如下:


//1.定义一个类实现Callable接口
public class MyCallable implements Callable<String> {
    private int n;
    public MyCallable(int n){
        this.n = n;
    }
    //2.重写call方法
    @Override
    public String call() throws Exception {
        //描述线程的任务,返回线程执行后的结果
        //求1-n的和返回
        int sum = 0;
        for (int i = 0; i <= n; i++) {
            sum += i;
        }
       return "线程求出1-" + n + "的结果是:" + sum + "";
    }
    
 //再定义一个测试类   
public class ThreadTest4 {
    public static void main(String[] args) throws Exception{
        //3.创建一个Callable的对象
        Callable<String> callable = new MyCallable(100);
        //4.把Callable的对象封装成一个FutureTask对象(任务对象)

        //未来任务对象的作用?
            //(1):是一个任务对象,实现了Runnable接口
            //(2):可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后的结果。
        FutureTask<String> futureTask = new FutureTask<>(callable);

        //5.把任务对象交给一个Thread对象
        new Thread(futureTask).start();



        Callable<String> callable1 = new MyCallable(200);
        FutureTask<String> futureTask1 = new FutureTask<>(callable1);
        new Thread(futureTask1).start();

        //6.获取线程执行完毕后返回的结果
        //注意:如果执行到这儿,上面的线程还没执行完毕
            //这里的代码会暂停,等待上面的线程执行完毕后才会获取结果
        String s = futureTask.get();
        System.out.println(s);

        String s1 = futureTask1.get();
        System.out.println(s1);
    }


}

打印结果如下:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值