多线程——认识线程(Thread)

目录

·前言

一、第一个多线程程序

1.程序编写

2.介绍jconsole

二、创建线程

1.继承Thread类

①重写run方法

②重写run方法,使用匿名内部类

2.实现Runnable接口

①重写run方法

②重写run方法,使用匿名内部类

③使用 lambda 表达式

三、多线程的优势

·结尾


·前言

        在前面文章我介绍了线程是什么,线程存在的意义还有线程与进程的区别,在本篇文章将会带大家在Java中进一步认识线程,会用Java语言写第一个多线程的程序,介绍在Java中如何创建线程,还要结束多线程编程的优势。

一、第一个多线程程序

1.程序编写

        在下面的程序中,我会让大家感受到多线程程序和普通程序的区别:

  1. 每个线程是独立的执行流;
  2. 多个线程之间是“并发”执行的。

         程序代码如下所示:

// 1. 创建自己的类,继承自 Thread
class MyThread extends Thread {
    // run 方法是该线程的入口方法
    @Override
    public void run() {
        while (true) {
            // currentThread.getName()这个方法是获取当前线程的名字
            System.out.println("hello " + currentThread().getName());
            try {
                // sleep()这个方法会让当前线程进入休眠,()中参数是ms,为了减慢循环频率
                // 这个方法可能抛出异常,所以需要用 try-catch包住
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class ThreadDemo {
    public static void main(String[] args) {
        // 2. 根据上面创建的类,创建出实例
        Thread t1 = new MyThread();
        // 3. start(),这个方法用来启动线程,这才是创建出线程
        //    调用这个方法,才会真正调用系统 api ,在系统内核中创建出线程
        t1.start();

        // 在main里启动另一个死循环,直观感受两个线程在"并发"执行
        while (true) {
            System.out.println("hello " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

        程序运行结果如下图所示:

        由上图两个线程中的循环不断打印里面的内容,可以看出这两个线程是“并发”执行。

2.介绍jconsole

        jconsole是一个很方便的工具,可以利用这个工具来查看我们创建线程的相关信息,他的位置在我们的jdk的bin目录下,如下图所示:

        下面介绍一下jconsole的使用过程:

        关于使用jconsole需要补充介绍几点:

  1. jconsole 只能列出Java的进程,其他不是Java的程序无法分析;
  2. 打开 jconsole 可能不显示任何进程,可以使用管理员的方式来启动 jconsole(鼠标右键选择jconsole,选择“以管理员的身份运行”);
  3. 上面图中可以看见,我们创建的线程名叫 Thread-0 ,但是代码中,实例化的对象名叫t,其实答案就在刚才说的话里,我们创建的是一个对象,t是对象的名,不是我们所创建的线程名,我们创建的线程名默认叫 Thread-0、Thread-1……;
  4. 上图中,我们会发现,除了我们手动创建的线程,和main线程外,还有很多别的线程,这些线程都是JVM自带的线程,他们需要完成一些其他工作,比如垃圾回收,监控统计各种指标(如果代码出问题,可以通过这些指标给我们提供一些线索)等……;
  5. 线程是不断执行的,jconsole 是在我们选择线程的一瞬间,对线程来个“快照”,就把这一瞬间的状态展开显示出来。

        其实不光是 jconsole 可以看到线程的情况,在 idea 调试器中,也可以看道线程的情况,只不过我个人感觉 jconsole 比较方便,所以就不再介绍 idea 中的调试器了。

二、创建线程

        下面我来介绍几种Java中创建线程的方式:

1.继承Thread类

①重写run方法

// 继承 Thread 重写 run 方法
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello thread!!!");
    }
}

public class ThreadDemo2 {
    public static void main(String[] args) {
        // 实例化一个线程对象
        Thread t = new MyThread();

        // 真正的去申请系统线程,参与 CPU 调度
        t.start();
    }
}

②重写run方法,使用匿名内部类

// 继承 Thread ,重写 run 方法,使用匿名内部类
public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            // 指定线程任务
            @Override
            public void run() {
                System.out.println("hello thread");
            }
        };

        // 真正的去申请系统线程,参与 CPU 调度
        t.start();
    }
}

2.实现Runnable接口

①重写run方法

// 创建一个 Runnable 的实现类,并实现 run 方法
// Runnable 主要描述的是线程的任务
class MyThread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("hello thread!!!");
    }
}

public class ThreadDemo4 {
    public static void main(String[] args) {
        // 实例化 Runnable 对象
        Runnable runnable = new MyThread2();
        // 实例化线程对象,并绑定任务
        Thread t = new Thread(runnable);
        // 真正的去申请系统线程,参与 CPU 调度
        t.start();
    }
}

②重写run方法,使用匿名内部类

// 通过 Runnable 匿名内部类创建一个线程
public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            // 指定线程任务
            @Override
            public void run() {
                System.out.println("hello thread!!!");
            }
        });
        // 申请系统线程参与CPU调度
        t.start();
    }
}

③使用 lambda 表达式

        lambda表达式可以简化函数式接口的使用。什么是函数式接口呢?就是一个有且只有一个抽象方法的普通接口,Runnable接口就是一个函数式接口,所以可以使用 lambda 表达式来创建 Runnable 的子类对象,进而创建一个线程,代码如下所示:

// 通过 lambda 表达式的方式创建一个线程
public class ThreadDemo6 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            // 指定任务: 打印 hello thread!!
            System.out.println("hello thread!!");
        });
        // 申请系统线程参与CPU调度
        t.start();
    }
}

        上述的五种创建线程的方式,我本人比较喜欢用 lambda 表达式的方式进行创建线程,因为这种方式比较简便。 

三、多线程的优势

        使用多线程的方式可以加快运行速度,可以举一个例子,如下图所示:

        在一个房间中,有100只烤鸡,此时需要房间中的滑稽老哥把这些鸡给吃完,可想而知,这样吃下去的速度会很慢,为了加快吃鸡效率,我们可以再邀请一个个滑稽老哥一起吃鸡,如下图所示: 

        这样,一个滑稽老哥吃50只烤鸡,效率明显就快了很多,以此类推,我们还可以再多邀请几个滑稽老哥,如下图所示:         现在,邀请了更多的滑稽老哥,吃鸡的速度变得更快了,但是,不是说引入的滑稽老哥越多效率就会越快,如下图所示:

        上图我们可以看出,邀请的滑稽老哥到达一定数量之后,再邀请更多的滑稽老哥,吃鸡的效率也没有办法继续提升了,这是因为桌子坐不下了。

        上面列举的例子中,滑稽老哥就是我们的线程,烤鸡就是我们要执行的任务,多线程的优势就是通过引入多个线程可以加快执行任务的效率,但是也不能引入太多的线程,就像上图所示那样,线程数量太多,各个线程之间就会互相竞争CPU的资源(CPU核心数有限),这样非但不会提高效率,反而还会增加调度的开销。 

·结尾

        文章到这就快结束了,本篇文章是在Java中利用多线程编程的一个初始篇章,这里介绍了创建线程的几种方式,编写的第一个多线程程序,介绍了多线的优势,在下一个篇文章中我会对java中Thread类再进行进一步的讲解,如果本篇文章对你有帮助的话,希望能三连支持一下咯,您的支持就是我最大的动力,我们下一篇文章再见吧,┏(^0^)┛~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值