IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 初始多线程 -> 正文阅读

[Java知识库]初始多线程

目录

一.线程的概念

1.什么是线程

2.引入多线程的目的

3.了解线程和进程的区别

4.了解多线程的执行

二.学习使用Java来创建线程

1.学习创建线程的几种方法

(1)通过继承Thread类来创建线程

(2)实现Runnable接口来创建线程

(3)使用匿名内部类来创建线程

(4)使用lambda表达式创建线程

三.了解Thread类的常见方法即如何使用

1.Thread类的常见构造方法

2.Thread常见的属性

3.线程的启动

4.线程的中断

(1)中断线程的2种方法

(2)使用自定义标记来通知线程结束

(3)使用interrupt()方法来通知线程结束

?(4)有关Thread.interrupted()和Thread.currentThread().isInterrupted()的区别

2.Thread.currentThread().isInterrupted()

5.线程的等待和休眠(join(),sleep()方法的使用)

(1)为什么需要线程进行等待

(2)线程等待的方法

(3)线程等待实例

?(4)线程休眠(sleep())

6.观察线程的所有状态

7.yield()礼让线程


一.线程的概念

1.什么是线程

一个线程就是一个 "执行流". 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 "同时" 执行着多份代码。

2.引入多线程的目的

为了并发编程,而且线程比进程轻量;线程的创建,销毁,调度比进程创建,销毁,调度快。

3.了解线程和进程的区别

(1)其中进程是包含线程的,每个进程至少有一个线程,是主线程。

(2)进程与进程之间不共享内存空间,进程中的线程之间共享内存空间。

(3)进程是系统分配资源的最小单位,线程是系统调度的最小单位。

4.了解多线程的执行

如果对于一个从0加到1亿这个简单的操作来说,使用之前的main方法来执行,假设这里的执行时间为T,如果使用多线程来并发执行,假设我们这里创建了10个线程,那么相当于是每个线程只需要执行1千万的加法操作即可,大概效率提高了10倍,这就是使用多线程的好处,目的当然是为了提高程序的执行效率。

二.学习使用Java来创建线程

1.学习创建线程的几种方法

这里在创建线时需要注意:首先需要重写run方法,之后启动线程通过调用start方法来进行启动

(1)通过继承Thread类来创建线程

运行结果:

?代码:

package thread.example;

public class CreatThread1 extends Thread {
    @Override
    public void run() {
        System.out.println("线程执行代码");
    }

    public static void main(String[] args) {
        CreatThread1 thread = new CreatThread1();
        thread.start();
    }
}

(2)实现Runnable接口来创建线程

注意:在实现该接口,需要重写run方法,同时还需要借助Thread来进行启动。

执行结果:

?代码:

package thread.example;

public class CreateThread2 implements Runnable {
    @Override
    public void run() {
        System.out.println("创建的线程执行");
    }

    public static void main(String[] args) {
        Thread thread = new Thread(new CreateThread2());
        thread.start();
    }
}

(3)使用匿名内部类来创建线程

运行结果:

?代码:

package thread.example;

public class CreateThread {
    public static void main(String[] args) {
        //使用匿名内部类来创建线程
        //直接创建Thread子类对象
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("Thread创建的线程");
            }
        };
        thread.start();
        //创建Runnable子类对象
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable创建的线程");
            }
        });
        thread2.start();
    }
}

(4)使用lambda表达式创建线程

运行结果:

?代码:

package thread.example;

public class CreateThread3 {
    public static void main(String[] args) {
        //使用lambda表达式创建线程
        Thread thread = new Thread(()->{
            System.out.println("lambda表达式创建线程");
        });
        thread.start();
    }
}

三.了解Thread类的常见方法即如何使用

1.Thread类的常见构造方法

方法说明
Thread()?创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)?使用 Runnable 对象创建线程对象,并命名

2.Thread常见的属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否为后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

属性的用途了解:

  • ID 是线程的唯一标识,不同线程不会重复。
  • 名称是各种调试工具会用到。
  • 状态表示线程当前所处的一个情况。
  • 优先级高的线程理论上来说更容易被调度到。
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  • 是否存活,即简单的理解,为 run 方法是否运行结束。
  • 线程的中断,也就是被阻塞到中断那里等待,直到得到执行权继续执行。
    ?

3.线程的启动

创建一个线程是通过重写Thread中的run方法来实现,其中的run方法重写后相当于是线程已经准备就绪,只有调用start方法后操作系统才会在底层创建出一个线程,之后才会真正的执行起来。

4.线程的中断

(1)中断线程的2种方法

  • 通过共享标记来进行通知(自定义变量作为标记需要使用volatile修饰)
  • 通过interrupt()方法进行通知

(2)使用自定义标记来通知线程结束

package thread.example;

public class InterruptThread {
    public static volatile boolean flag = false;//设置标记来中断线程
    public static void main(String[] args) throws InterruptedException {
        //这里使用匿名类来创建线程
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                while (!flag) {
                    System.out.println("线程正在执行");
                    try {
                        Thread.sleep(10*100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("线程执行结束");
            }
        };
        thread1.start();
        //通过sleep方法来阻塞另一个线程
        Thread.sleep(10*1000);
        System.out.println("通知thread1结束");
        flag = true;
    }
}

(3)使用interrupt()方法来通知线程结束

可以通过使用Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位。因为Thread内部也是通过变量来作为线程中断的标志。

有关该方法的使用如下:

方法说明
public void interrupt()?中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted()?判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isInterrupted()
?判断对象关联的线程的标志位是否设置,调用后不清除标志位

package thread.example;

public class InterruptThread2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            public void run() {
                //两种方法都可以
//                while (!Thread.interrupted()) {
                while (!Thread.currentThread().isInterrupted()){
                    System.out.println("thread执行");
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;//跳出循环
                    }
                }
                System.out.println("thread结束");
            }
        };
        thread.start();
        Thread.sleep(1000);
        System.out.println("线程结束");
        thread.interrupt();

    }
}

?(4)有关Thread.interrupted()和Thread.currentThread().isInterrupted()的区别

1.Thread.interrupted()

会清除标记位,如下所示:

package thread.example;

public class InterruptThread2 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(){
            @Override
            public void run() {
                //两种方法都可以
//                while (!Thread.interrupted()) {
                while (!Thread.currentThread().isInterrupted()){
                    System.out.println("thread执行");
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;//跳出循环
                    }
                }
                System.out.println("thread结束");
            }
        };
        thread.start();
        Thread.sleep(1000);
        System.out.println("线程结束");
        thread.interrupt();

    }
}

2.Thread.currentThread().isInterrupted()

不会清除标记位,如下所示:

package thread.example;

public class InterruptThread3 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i=0; i<10; i++) {
                //清除标记位
                System.out.println(Thread.currentThread().isInterrupted());
            }
        });

        thread.start();
        thread.interrupt();//相当于是将标记为设为true

    }
}

注意:如果使用使用这两种通知方式的时候,如果线程里面包含wait/join/sleep 等方法而阻塞挂起,这时候就会抛出一个异常,从而都会清除标记位,这时候有2种选择,一个是忽略该异常,继续执行;另一个是跳出该异常,结束循环。

5.线程的等待和休眠(join(),sleep()方法的使用)

(1)为什么需要线程进行等待

因为多线程是抢占式随机执行,但是有时候我们需要上一个线程的结果才能执行到下一个线程,这时候就需要线程进行等待,等到上一个执行结束再执行下一个线程。

(2)线程等待的方法

方法解释
public void join()?等待线程结束
public void join(long millis)?等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)?同理,但可以更高精度

(3)线程等待实例

package thread.example;

public class WaitThread {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("thread1执行");
                }
            }
        };
        Thread thread2 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("thread2执行");
                }
            }
        };
        thread1.start();
        thread1.join();
        thread2.start();
    }
}

?(4)线程休眠(sleep())

线程休眠也相当于是阻塞,只不过,这个阻塞是有时间限制的,这个时间可以进行设置,一般休眠时间大于设置的时间。

可以通过Thread.sleep()直接进行调用。

6.观察线程的所有状态

  • NEW: 安排了工作, 还未开始行动。
  • RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作。
  • BLOCKED: 表示等待获取锁,相当于排队等着其他事情。
  • WAITING: 表示等待其他线程发来通知,如果没有通知,相当于是死等,相当于排队等着其他事情。
  • TIMED_WAITING: 表示等待其他线程发来通知,而且这个等待也有时间限制,相当于排队等着其他事情。
  • TERMINATED: 工作完成了。

7.yield()礼让线程

使用该方法相当于是将当前自己所持有的cpu让出来然后自己重新排队等待。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-06 12:48:23  更:2022-03-06 12:51:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:51:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码