Java 多线程

本文详细介绍了Java中进程与线程的概念,包括它们的区别及如何创建多线程。通过示例代码展示了三种创建线程的方法:继承Thread类、实现Runnable接口和实现Callable接口。

1、进程和线程

进程是系统中正在运行的一个程序,是系统资源分配的单位,每个进程都被单独分配有一块独立的内存空间。

线程是是CPU调度和执行的最小单位,每个进程中至少包含有一个线程。

Java程序都是多线程程序,可以通过下下面方法来获取当前的所有活动线程。

public class test {
    public static void main(String[] args) {
        //获取线程管理
        ThreadMXBean mx = ManagementFactory.getThreadMXBean();
        //获取所有活动线程
        ThreadInfo[] infos = mx.dumpAllThreads(false, false);
        //打印输出
        for(ThreadInfo info : infos) {
            System.out.println(info.getThreadId() + "  " + info.getThreadName());
        }
    }
}
1  main
2  Reference Handler
3  Finalizer
4  Signal Dispatcher
5  Attach Listener
11  Common-Cleaner
12  Monitor Ctrl-Break

上面一段简单的测试代码中,可以看到有 main 线程用来执行我们写的 main 方法。除此之外后台还启动了一些其他的线程用来保证程序的运行。

一个进程通常包含有多个线程,同一个进程中的线程共用该进程的内存空间,而两个进程之间的内存空间是相互独立的。由于一个进程中的线程共用一块内存空间,所以线程间的上下文切换很快,资源开销较少,而进程间的通信需要通过其他方式来实现。

2、多线程

在一个进程中需要同时处理多个任务时,可以建立多个线程来同时计算处理。

在只有一个CPU的计算机中,同一时间点只能处理一条命令,所以会在各线程之间来回切换处理任务,上图红线表示在某一个时间点 CPU 在调度执行对应的线程。所以实际上CPU并不是同时处理多个任务,只是由于在线程之间切换的频率很快,我们在感官上无法感受到这种切换过程,整个处理过程在我们看来就是在同时进行。

3、Java创建线程的 3 种方式

继承 Thread 类

第一步:定义类继承 Thread 类

第二步:重写 run 方法

第三步:创建对象调用 start 方法启动线程(若直接调用 run 方法则相当于正常调用方法,并不会创建线程执行)

class RaceThread extends Thread {    //定义类继承 Thread 类
    private String name;
    private int distance;
    public RaceThread(String name) {
        this.name = name;
        distance = 0;
    }
    @Override
    public void run() {     //重写 run 方法
        while(distance < 1000) {   //模拟 1000 米赛跑
            distance++;
            System.out.println(name + " 跑了 " + distance + " 米");
        }
    }
}
public class test {
    public static void main(String[] args) {
        //创建实例对象
        RaceThread t1 = new RaceThread("张三");
        RaceThread t2 = new RaceThread("李四");
        RaceThread t3 = new RaceThread("王五");
        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

可以看到在程序运行的过程中,并非某一个任务结束后执行下一个任务,而是三个任务在同时进行。

实现 Runnable 接口

第一步:定义类实现 Runnable 接口

第二步:重写 run 方法

第三步:通过 Thread 对象代理启动线程

class RaceThread implements Runnable {      //定义类实现 Runnable 接口
    private String name;
    private int distance;
    public RaceThread(String name) {
        this.name = name;
        distance = 0;
    }
    @Override
    public void run() {     //重写 run 方法
        while(distance < 1000) {   //模拟 1000 米赛跑
            distance++;
            System.out.println(name + " 跑了 " + distance + " 米");
        }
    }
}
public class test {
    public static void main(String[] args) {
        //创建实例对象
        RaceThread t1 = new RaceThread("张三");
        RaceThread t2 = new RaceThread("李四");
        RaceThread t3 = new RaceThread("王五");
        //通过 Thread 对象代理启动线程
        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();
    }
}

或者可以通过匿名内部类创建 Thread 对象启动线程,不需要定义类去继承 Runnable 接口。通常该线程只需要使用一次时使用,若多次使用会使得代码变得繁琐。

public class test {
    static int d = 0;
    public static void main(String[] args) {
        new Thread(new Runnable() {    //通过匿名内部类创建 Thread 对象
            @Override
            public void run() {    //重写 run 方法
                while(d < 1000) {
                    d++;
                    System.out.println("张三跑了 " + d + " 米");
                }
            }
        }).start();    //启动线程
    }
}

实现 Callable 接口

Callable 接口类似于 Runnable 接口,但是 Runnable 接口没有返回值且不能抛出被检查的异常。

第一步:定义类实现 Callable 接口,需要返回值类型

第二步:重写 call 方法,需要抛出异常

第三步:创建实例对象

第四步:创建 FutureTask 对象包装 Callable 接口,线程执行结束后可以获取返回值。

第五步:通过 Thread 对象代理启动线程。

class RaceThread implements Callable<Integer> {      //定义类继承 Callable 接口,确定返回值类型
    private String name;
    private int distance;
    public RaceThread(String name) {
        this.name = name;
        distance = 0;
    }
    @Override
    public Integer call() {     //重写 call 方法,有返回值
        while(distance < 1000) {   //模拟 1000 米赛跑
            distance++;
            System.out.println(name + " 跑了 " + distance + " 米");
        }
        return distance;    //返回跑完的距离
    }
}
public class test {
    public static void main(String[] args) {
        //创建实例对象
        RaceThread t1 = new RaceThread("张三");
        RaceThread t2 = new RaceThread("李四");
        RaceThread t3 = new RaceThread("老王");
        //创建 FutureTask 对象包装
        FutureTask<Integer> f1 = new FutureTask<>(t1);
        FutureTask<Integer> f2 = new FutureTask<>(t2);
        FutureTask<Integer> f3 = new FutureTask<>(t3);
        //通过 Thread 对象代理启动
        new Thread(f1).start();
        new Thread(f2).start();
        new Thread(f3).start();
        //线程运行结束后可以获取返回值
        try {
            //通过 get 方法获取返回值
            Integer d1 = f1.get();
            Integer d2 = f2.get();
            Integer d3 = f3.get();
            //输出返回值内容
            System.out.println("张三共跑完 " + d1 + " 米");
            System.out.println("李四共跑完 " + d2 + " 米");
            System.out.println("老王共跑完 " + d3 + " 米");
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

 运行过程与前面类似,线程运行结束后可以获取到返回值内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值