多线程(一)线程的介绍与创建

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43570367/article/details/102753285

一、线程与进程的区别

1.进程:是程序的一次执行过程,或是正在运行的一个程序 。由程序、数据和进程控制块三部分组成。比如 运行中的IDEA,vscode
2.线程:是进程中实际运作的单位,是一个程序内部的一条执行路径。

总结:一个操作系统可以同时执行多个任务,每个任务就是一个进程;一个进程可以执行多个任务,每个任务就是线程。

3.两者之间的关系:一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程,即主线程。多个线程共享进程的全部系统资源,同时线程还拥有自己独立的程序计数器、虚拟机栈、本地方法栈。

二、使用多线程的好处

1.进程之间不能共享内存;线程之间相互独立,且共享进程中的资源,提高计算机CPU的利用率。
2.多线程技术使程序的响应速度更快,增强用户的体验。

三、线程的创建和启动

1.继承Thread类 创建线程

  • 定义一个继承Thread类的子类;
  • 重写该类的run()方法,将线程执行的操作声明在run()方法里面;
  • 创建Thread类子类的对象;
  • 调用线程对象的start()方法来启动线程。
// 1.创建一个继承于Thread类的子类
class MyThread extends Thread {
    // 2.重写Thread类的run方法
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName()+": "+i);
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        // 3.创建Thread类子类的对象
        MyThread t1 = new MyThread();
        // 4.通过此对象调用start
        t1.setName("线程A");
        t1.start();

        MyThread t2 = new MyThread();
        t2.setName("线程B");
        t2.start();
    }
}

2.实现Runnable接口 创建线程

  • 定义一个实现了Runnable接口的类;
  • 重写run()方法,将线程执行的操作声明在run()方法里面;
  • 创建实现类的对象;
  • 将此对象传递到Thread类的构造器中创建Thread对象;
  • 调用线程对象的start()方法启动该线程。
// 1.创建一个实现Runnable接口的类
class MyThread implements Runnable {
    // 2.实现类去实现Runnable中的抽象方法run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        }
    }
}
public class ThreadTest2 {
    public static void main(String[] args) {
        // 3.创建实现类的对象
        MyThread m = new MyThread();
        // 4.创建Thread类的对象
        Thread t1 = new Thread(m);
        t1.setName("线程A");
        // 5.启动线程
        t1.start();
       
        Thread t2  = new Thread(m);
        t2.setName("线程B");
        t2.start();
    }
}

两种方式的比较:
两种方式都需要重写run(),将线程要执行的操作声明在run()中。
第一种方式是继承Thread类,因Java是单继承,如果一个类继承了Thread类,那么就没办法继承其它的类了。
第二种 实现的方式没有类的单继承性的局限性,实现的方式更适合来处理多个线程有共享数据的情况。所以实际开发就使用第二种方式。

3.使用Callable 和 Future 创建线程

从Jdk 1.5开始,Java 提供了Callable 接口,Callable接口提供了Call()方法作为线程的执行体。call()方法可以有返回值,也可以声明抛出异常,因此它可看作是Runable接口的增强版。

  • 创建一个Callable的实现类,实现Call 方法,将此线程需要执行的操作声明在Call方法里面;
  • 创建Callable 接口的实现类对象;
  • 将此对象传递到FuterTask构造器中,创建FuterTask 对象;
  • 创建Thread对象,调用start启动线程;
  • 调用FuterTask对象的get()方法来获得线程结束后的返回值;
class MyThread implements Callable {
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 0; i <= 20; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            sum += i;
        }
        return sum;
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        MyThread m = new MyThread();
        FutureTask futureTask = new FutureTask(m);
        Thread t = new Thread(futureTask);
        t.start();
        // 获取线程返回值,此时捕获异常
        try {
            Object sum = futureTask.get();
            System.out.println("1-100内所有整数的总和为:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下所示:

Thread-0:0
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-0:5
Thread-0:6
Thread-0:7
Thread-0:8
Thread-0:9
Thread-0:10
Thread-0:11
Thread-0:12
Thread-0:13
Thread-0:14
Thread-0:15
Thread-0:16
Thread-0:17
Thread-0:18
Thread-0:19
Thread-0:20
1-20内所有整数的总和为:210

对比三种创建线程的方式:
三种方式都可以实现多线程,但是前两种定义的方法没有返回值;Callable接口里定义的方法有返回值,call()可以抛出异常,被外面的操作捕获,获取异常的信息。

猜你喜欢

转载自blog.csdn.net/weixin_43570367/article/details/102753285