Java 多线程学习

导言

线程的创建有三种方法,第一种方法是继承Thread类,第二种方法是实现Runnbale接口,第三种是实现Callable接口

目录

导言

如何创建线程

 第一种方法,继承 Thread 类

第二种方法,

实现 Runnable 接口

第三种方法,实现 Callable 接口

总结一下


如何创建线程

 第一种方法,继承 Thread 类

实例代码

/**
 * TestThread1 类
 * 操作人:小白
 * 日期:2021/10/11
 * 时间:14:41
 * 第一个创建线程的方法:继承Thread类
 * 1.继承 Thread 类
 * 2.重写 run() 方法
 * 3.创建对象
 * 4.调用 start() 方法,开启线程
 */
public class TestThread1 extends Thread{
    @Override
    // 重写 run() 方法
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("I'm libra,I'm " + i + ".");
        }
    }

    public static void main(String[] args){

        // 创建对象
        TestThread1 testThread1 = new TestThread1();

        // 调用 start() 方法
        testThread1.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("I'm ragel,I'm " + i + ".");
        }
    }
}

 运行后结果图

我们可以看到线程(Thread)创建后并没有被立即执行,而是先打印了几个主方法内的再去执行了它,因为线程创建了不一定立即执行,需要遵守CPU调度规则,如果只有一个CPU,也就是单核的情况,那就会以时间切片的形式使其达到同时执行的情况,其实本质上不是,但因为跳转的很快,我们可以认为其是。

如果我们不创建线程,用下面这样的方式去输出

运行结果

 

可以看到如果不创建线程,就会按顺序一步一步地输出,而创建了线程,就会遵守CPU调度规则,抢占式执行

第二种方法,

实现 Runnable 接口

实例代码

/**
 * TestThread2 类
 * 操作人:小白
 * 日期:2021/10/11
 * 时间:17:04
 * 实现 Runnable 接口
 */
public class TestThread2 implements Runnable{
    // 重写run()方法
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("I'm Libra,I'm " + i);
        }
    }

    public static void main(String[] args) {
        // 创建Runnable接口实现类对象
        TestThread2 testThread2 = new TestThread2();
        // 创建线程对象并传入实现类对象
        Thread thread = new Thread(testThread2);
        // 用线程对象去启动线程
        thread.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("I'm Ragel,I'm " + i);
        }
    }
}

 运行结果图

 

实现 Runnable 接口和继承Thread类是一样的,原因是Thread类也实现了Runnable接口,那么自然而然的也就有这两个方法来实现创建线程了,但是我们推荐实现Runnable接口,因为Java中是单继承的,如果使用继承 Tread 类的话,就会出现OOP单继承局限性,会增加两个类之间的耦合性,会导致父类的改动直接影响子类,并且无法再次继承,因此我们推荐实现 Runnable 接口,完美解决了这个问题。

第三种方法,实现 Callable 接口

实例代码

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * TestCallable 类
 * 操作人:小白
 * 日期:2021/10/11
 * 时间:19:34
 * 实现 Callable 接口
 * 1.实现 Callable 接口
 * 2.重写 call() 方法
 * 3.创建 FutureTask 对象
 * 4.启动线程
 */
public class TestCallable implements Callable<String> {
    private int tickt = 100;

    @Override
    public String call() throws Exception {
        String result;
        while (tickt > 0){
            System.out.println(Thread.currentThread().getName() + "抢到了第 " + tickt-- + " 张票");
        }
        result = (String) "票已卖光。";
        return result;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable mc = new TestCallable();

        FutureTask<String> ft = new FutureTask<>(mc);
        FutureTask<String> fe = new FutureTask<>(mc);
        new Thread(ft).start();
        new Thread(fe).start();
        // 可以用 get() 获取返回值
        String result = ft.get();
        System.out.println(result);
    }
}

运行结果 

Callable 接口与 Runnable 接口对比

1.Callable 接口中,需要重写的方法是 call(),而 Runnable 接口中,需要重写的方法是 run()

2.Callable 接口有返回值,而 Runnable 接口没有

3.Callable 接口可以抛出异常,而 Runnable 接口没有

总结一下

有三种方法创建线程

1.继承 Thread 类,操作简单,但是会有OOP单继承局限性,代码耦合度较高

2.实现 Runnable 接口,操作较1复杂,但不具有OOP单继承局限性

3.实现 Callable 接口,操作复杂,但 call() 方法有返回值,可以抛出异常

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值