初学者-----多线程(二)

每天知识多一点 ! 每天烦恼少一点 !

在这里插入图片描述


前言

今天我们继续来了解多线程中的Thread类,本篇内容我们通过讲解以下几个内容:

  • Thread的常见构造方法
  • Thread的几个常见属性
  • 启动一个线程------start()
  • 中断一个线程
  • 等待一个线程------join()
  • 获取当前线程引用
  • 休眠当前线程

所涉及到的知识点太多,本篇中出现很多代码。通过代码动手的编写我们能够更好的理解!!

在这里插入图片描述


Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。
每个执行流,也需要有一个对象来描述,而 Thread 类的对象 就是用来描述一个线程执行流 的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

1.Thread的常见构造方法

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("这是我的名字");
//在创建线程的时候,可以给线程起名字(名字是可以重复的)
//而且这种做的目的,也是方便我们之后调试
Thread t4 = new Thread(new MyRunnable(), "这是我的名字");

-------------------------------这里我们通过写一个自起名字的线程程序来更好的学习-------------------------------

这里通过 lambda 表达式创建一个线程,并且给它命名为 我的第一个测试线程

public class Demo4 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
           while(true){
               System.out.println("Hello");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        },"我的第一个测试线程");
    }
}

启动线程。开始延时打印hello

在这里插入图片描述

此时我们打开jdk中一个观察线程的工具jconsole.exe,我们会发现创建的线程已经成功运行起来了!

在这里插入图片描述

注意:我们在创建线程时所用到的 t 只是一个变量名,是在代码中存在的。而“我的第一个测试线程”才是线程的名字。而这个名字是既在代码中存在,又在程序运行中存在!!!

2.Thread的几个常见属性

在这里插入图片描述

  1. getId()获取到的ID这个是java中给Thread对象安排的身份标识,和操作系统内核中的PCB的pid,操作系统提供的线程API中的线程id都不是一回事!!身份标识可以有多个,在不同环境下,会使用不同的标识。例如
    一个线程:在jvm中有一个id,在操作系统的线程API也有一个id,在内核pcb中还有一个id
  2. getName()中的name则是在构造方法中的name
  3. 后台线程不会阻止线程退出,如果main等其他的前台线程执行完了,这个时候后台线程没执行完,进程也会退出。像微信步数这样的程序中我们就可以使用后台线程
  4. isAlive()用来判定内核的线程在不在

我们通过下面这段代码来更好的了解一下Thread的这几个常见的属性

public class Demo5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
           while(true){
               System.out.println("hello");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        },"这是我的第二个测试线程");

        t.start();

        System.out.println(t.getId());
        System.out.println(t.getName());
        System.out.println(t.getPriority());
        System.out.println(t.getState());
        System.out.println(t.isDaemon());
        System.out.println(t.isAlive());
        System.out.println(t.isInterrupted());
    }
}

如图所示,这里所打印出来的结果就对应着上面每一项属性

在这里插入图片描述

3.启动一个线程------start()

之前我们已经看到了如何通过重写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。
覆写 run 方法是提供给线程要做的事情的指令清单
线程对象可以认为是小明同学把A,B叫过来了
而调用 start() 方法,就是喊一声:”行动起来!“,这时候线程才真正独立去执行了。
在这里插入图片描述

这里大家要区分清楚 run() 和 start() 二者的区别:
直接调用run方法呢,并没有创建线程,只是在原来的线程中运行代码
而调用start方法,则是创建了线程,在新线程中执行代码(是和原来的线程并发的)

通过下面这段代码可以更直观的看出二者的区别

class MyThread2 extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("调用run方法");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static class Demo6 {
        public static void main(String[] args) {
            Thread t = new Thread();
            t.start();
          //t.run();
            while (true) {
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }   
        }
    }
}

4.中断一个线程

A和B一旦进到工作状态,他就会按照行动指南上的步骤去进行工作,不完成是不会结束的。但有时我们需要增加一些机制,例如小明的女朋友突然来电话了,说转账的对方是个骗子,需要赶紧停止转账,那小明该如何通知A和B停止呢?这就涉及到我们的停止线程的方式了。

1.第一种方法

		直接自己定义一个标志位,作为线程是否结束的标记
public class Demo7 {
    private static boolean a = false;

    public static void main(String[] args) {
        Thread t = new Thread(()->{
            while(!a){
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t线程执行完毕!");
        });

        t.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        a = true;
        System.out.println("设置了标志,让线程t结束!");
    }

}

2.第二种方法

		我们也可以使用标准库中自带的一个标志位
public class Demo8 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                //currentThread是Thread类的静态方法,通过这个方法就可以拿到当前线程的实例
                //isInterrupted是判定标志位
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                    break;
                }
            }
            System.out.println("t线程执行完毕!");
        });

        t.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //在主线程中,通过t.interrupt来中断这个线程,设置标志位为true
        t.interrupt();

        System.out.println("设置了标志,让线程t结束!");
    }
}

5.等待一个线程------join()

线程之间的调度顺序是不确定的。但是我们可以通过一些特殊的操作方法,来对线程的执行顺序做出干预。

我们依然通过代码来更清楚的认识一下:

public class Demo9 {
    public static void main(String[] args) {
        Thread t = new Thread(() ->{
            for(int i =0;i < 5;i++){
                System.out.println("hello world");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();

        System.out.println("main 线程 join之前");
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main 线程 join之后");
    }
}

在这里我们就能看到打印 main 线程 join 之后 这个语句是在t线程执行结束之后才进行打印的。
在这里插入图片描述

这里还有关于Join() 的其他几种写法,大家可以根据上述代码进行修改然后学习一下!!
在这里插入图片描述

6.获取当前线程引用

对于这个方法呢,我们就很熟悉了
在这里插入图片描述
我们依然还是上代码! ! !

public class Demo10 {
	public static void main(String[] args) {
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName());
	}
}

我们可以看到当前所引用的是我们的main线程,然后通过上述代码可以将线程所引用的对象打印出来
在这里插入图片描述

7.休眠当前线程

这个也是我们比较熟悉一组方法,但是有一点要记得,因为线程的调度是不可控的,所以,这个方法只能 保证实际休眠时间是大于等于参数设置的休眠时间的(划重点!!)。

在这里插入图片描述
我们还是通过代码来具体演示:

public class Demo11 {
	public static void main(String[] args) throws InterruptedException {
		System.out.println(System.currentTimeMillis());
		Thread.sleep(3 * 1000);
		System.out.println(System.currentTimeMillis());
}
}

总结

到这里呢,我们本篇内容就结束了。通过对Thread类中我们常用到的一些构造方法,常见的属性等进行了介绍,并且每一块都附上了代码。我们通过代码的演示,能够更清楚、更详细、更深刻的了解和学习到它的精华。希望各位小伙伴们能够将代码手动敲一遍,将这些知识都容纳到自己的大脑中!
我是初学者,下期再见!!

你对他人的酸,是你前进不放弃最好的理由!!!

在这里插入图片描述

  • 39
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值