多线程的创建及状态描述

一、什么是线程

💡线程是程序执行流的最小单元💕💕. 它包含在进程之中,是进程中的实际运行单位,在Unix System V及SunOS中也被称为轻量进程(lightweight processes). 一个进程中可以并发多个线程,每个线程并行执行不同的任务🕛🕛🕛. 虽然多进程也能实现并发编程, 但是线程比进程更轻量(创建线程比创建进程更快,销毁线程比销毁进程更快,调用线程比调用进程更快 ).🫠🫠🫠


进程和线程的区别:

  • 进程里面包含线程, 每个进程至少包含一个线程,即主线程.
  • 同一个进程的线程之间可以共享同一个内存空间,两个进程之间不能共享同一块内存空间.
  • 进程是系统分配资源的最小单位,线程是系统调度的最小单位.

二、多线程使用场景

1.专用服务器

🙈🙈🙈 比如用于大型网游服务器的搭建,游戏画面实际需要 CPU 大量的在背后运算,使用多线程,可以更好的利用CPU多核计算资源,从而提高效率!!

2.异步处理

👁️‍🗨️👁️‍🗨️👁️‍🗨️比如发博客,记录日志,读写硬盘等场景,这些业务需要花大量的时间进行等待,而 CPU 此时任务量小,合理利用CPU资源,也能提高效率!!

三、创建线程的5种方法

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

class MyThread extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("继承 Thread 类");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}

重写 run() 方法创建出了一个线程对象,但此时线程对象并没有运行起来,相当于运动员已准备就绪. 此时需要调用 start() 方法,打出发令枪,线程才真正执行起来. 虽然调用 run() 方法也能得到相同结果,但系统内核并没有创建线程对象.

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

class MyThread1 implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("实现 Runnable 接口");
        }
    }
}
public class Test1 {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyThread1());
        thread.start();
    }
}

使用 jconsole 命令观察线程执行状态,
路径地址C:\ProgramFiles\Java\jdk1.8.0_191\bin\jconsole.exe.

名称: Thread-0
状态: TIMED_WAITING
总阻止数: 0, 总等待数: 32
堆栈跟踪:
java.lang.Thread.sleep(Native Method)
MyThread1.run(Thread2.java:14)
java.lang.Thread.run(Thread.java:748)

💡3. 匿名内部类创建 Thread 子类对象.

public class Test2 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("匿名内部类创建 Thread 子类对象");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        thread.start();
    }
}

休眠当前线程,可以调用 sleep() 方法,因为线程是随机调度的,实际休眠时间是大于等于设置的休眠时间的,也就是说,线程可能休眠完毕不会立即执行的.

💡4. 匿名内部类创建 Runnable 子类对象.

public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println(" 匿名内部类创建 Runnable 子类对象");
                }
                System.out.println("线程结束");
            }
        });
        thread.start();
        Thread.sleep(3000);
        thread.interrupt();

    }

😋😋中断线程有两种方式,可以自己设定标记位来判断是否暂停当前线程,也可以调用 interrupt() 方法来通知.

1.如果thread线程没有处在阻塞状态,interrupt就会修改标记位.
2.如果thread线程处于阻塞状态, interrupt就会抛出异常信息,我们可以处理完毕任务之后,再跳出循环.

📢📢📢注意: 使用 interrupted() 方法判断当前线程的标志位是否设置,调用后清除标志位. 使用 isInterrupted() 方法调用后不清除标志位.

💡5. Lambda 表达式,理解困难,但是代码量是最少的.

public class Test4 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            System.out.println("lambda 表达式");
        });
        System.out.println(thread.getState());
        thread.start();
    }
}

查看线程当前的状态,可以调用 getState() 方法,线程的状态一般分为:NEW 、 RUNNABLE 、 TERMINATED 、WAITING 、READY(就绪)、 BLOCKED 、 TIMED_WAITING几种状态.
🔽🔽🔽

NEW: 创建好Thread对象,但系统里并没有线程.
RUNNABLE: 线程可能正在运行中,也可能没在CPU上运行.
WAITING: 阻塞状态,线程中调用了 wait() 方法.
BLOCKED: 阻塞状态,线程中调用了 Synchronized() 方法.
TIMED_WAITING: 阻塞状态,线程中调用了 sleep() 方法.
TERMINATED: 线程已经执行完毕,系统里的线程已经销毁,但线程对象仍然存在.

四、多线程的优势

💡数值a和b分别自增20_0000_0000次,观察它们的执行时间.

串行:

//串行
    public static void serial() {
        long str = System.currentTimeMillis();
        int a = 0;
        for (int i = 0; i < count; i++) {
            a++;
        }
        int b = 0;
        for (int i = 0; i < count; i++) {
            b++;
        }
        long end = System.currentTimeMillis();
        System.out.println("时间为:"+(end-str));
    }

并发:

 public static void concurrency() {
        //并发
        long str = System.currentTimeMillis();

        Thread t1 = new Thread() {
            @Override
            public void run() {
                int a = 0;
                for (int i = 0; i < count; i++) {
                    a++;
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                int b = 0;
                for (int i = 0; i < count; i++) {
                    b++;
                }
            }
        };
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("时间为:"+(end-str));
    }

等待一个线程,可以调用 join() 方法,考虑到线程是随机调度的,如果t1, t2 不执行完毕的话,直接调用currentTimeMillis() 方法,获取的时间是不合理的.
结果:

此时,可以看出多线程在解决 20 亿数据自增的时候,效率明显高于串行, 这里的运行结果也不绝对,是根据自己电脑的配置和系统后台的运行程序数量决定的.

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

web图解

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值