Java——初识多线程

目录

  • 认识进程和线程
    • 为什么出现线程
    • 多线程和多进程的区别
  • 线程的创建
    • 1. 继承Thread类,重写run()方法
    • 2. 实现Runnable接口,重写run()方法
    • 3. 实现Callable接口,重写call()方法
    • Runnable接口和Callable接口的区别
    • 小练习:12306卖车票

认识进程和线程

  • 进程指的一段正在运行的程序,一个程序运行中可以执行多个任务,任务称之为线程
  • 进程是程序执行过程中资源分配和管理的最小单位 线程是cpu执行的最小单位
  • 进程拥有自己的独立的地址空间,每启动一个线程,系统就会分配地址空间
  • 进程可以拥有多个线程,各个线程之间共享程序的内存空间

为什么出现线程

在多线程操作系统中,通常是在一个进程中包括多个线程,每个线程都是独立调度和分派的基本单位。资源由进程拥有,线程不拥有资源。同一个进程之间的线程切换不会导致进程的切换,只有不同进程间的线程切换才会导致进程切换。而且线程的切换则仅需保存和设置少量寄存器内容,不会同进程切换需求创建和销毁进程控制块等,所以非常迅速,所以其十分适合高并发环境。

多线程和多进程的区别

区别 多进程 多线程
地址空间 独立的地址空间 共享本进程的地址空间
资源拥有 资源是独立的 共享本进程的资源
导管 进程崩溃后,不会对其他进程产生影响 线程崩溃会影响整个进程
执行过程 每个独立的进程程有一个程序运行的入口、顺序执行序列和程序入口 线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
单位 进程是资源分配的最小单位 线程是cpu调度的最小单位
创建/销毁开销
使用 追求系统更加稳定,选择进程 追求速度,频繁创建和销毁,选择线程
  • 线程之间的通信相比于进程之间的通信更有效 更容易
  • 多进程要比多线程健壮
  • 线程是轻量级的进程

线程的创建

1. 继承Thread类,重写run()方法

class MyThread extends Thread {
    @Override
    public void run(){
        //线程执行体
        while (true){
            System.out.println("吃饭");
        }
    }
}

class MyThread1 extends Thread {
    @Override
    public void run(){
        //线程执行体
        while (true){
            System.out.println("玩手机");
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        //创建线程对象
        Thread thread = new MyThread();
        Thread thread1 = new MyThread1();
        //启动线程
        thread.start();
        thread1.start();
    }
}

2. 实现Runnable接口,重写run()方法

class MyThread implements Runnable {
    @Override
    public void run(){
        //线程执行体
        while (true){
            System.out.println("吃饭");
        }
    }
}

class MyThread1 implements Runnable{
    @Override
    public void run(){
        //线程执行体
        while (true){
            System.out.println("玩手机");
        }
    }
}

public class TestThread {
    public static void main(String[] args) {
        //创建线程对象
        Thread thread = new Thread(new MyThread());
        Thread thread1 = new Thread(new MyThread1());
        //启动线程
        thread.start();
        thread1.start();
    }
}

3. 实现Callable接口,重写call()方法

Callable接口存在Executor框架中类,相比于Runnable更加强大
a.Callable可以在任务执行结束之后提供一个返回值
b.call方法可以抛出异常
c.运行Callable任务可以拿到一个Future对象,Future提供get方法
d.拿到返回值(异步)

  • 通过Callable和FutureTask创建线程:
    a.创建Callable接口的实现类,重写call方法
    b.创建Callable实现类的实例,使用FutureTask包装该实例
    c.将FutureTask实例作为参数创建线程对象
    d.启动该线程
    e.调用FutureTask的get方法获取子线程的执行结果
public class TestThread {
    public static void main(String[] args) {
        //2.创建Callable实现类的实例,使用FutureTask包装该实例
        Callable<Integer> callableTask = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(callableTask);
        //3.将FutureTask实例作为参数创建线程对象
        Thread thread = new Thread(task);
        //4.启动该线程
        thread.start();
        //5.调用FutureTask的get方法获取子线程的执行结果
        try {
            Integer integer = task.get();
            System.out.println("result: "+integer);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Runnable接口和Callable接口的区别

区别 Runnable Callable
函数返回值 run()无返回值 call()有返回值,支持泛型
异常处理 run()只能抛出运行时异常,且无法捕获处理 call()允许抛出异常,可以获取异常信息

小练习:12306卖车票

public class Web12306 implements Runnable{
    //票数
    private int ticketNums = 99;

    @Override
    public void run(){
        while (ticketNums > 0){
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ticketNums--);
        }
    }

    public static void main(String[] args) {
        //一份资源
        Web12306 web12306 = new Web12306();
        System.out.println(Thread.currentThread().getName());
        //多个代理
        new Thread(web12306,"码农").start();
        new Thread(web12306,"码畜").start();
        new Thread(web12306,"蚂蟥").start();
    }
}

你可能感兴趣的:(Java基础,笔记,实战,java,多线程,编程语言)