栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

初始多线程

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

初始多线程

目录

一.线程的概念

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让出来然后自己重新排队等待。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/755729.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号