title: "Thread"
date: 2019-07-18T19:05:14+08:00
本章内容为:《关于Thread类基础》
作者:nuoccc
java.lang
类 Thread
java.lang.Object
继承者 java.lang.Thread
所有已实现的接口:
Runnable
以上是 jdk 关于Thread的 视图
我们学习Thread类 就从提供的api入手
构造器
-
学一个类一般我们都是先学构造器,Thread有多个,但我们一般用两个
1.Thread(),默认构造器,用法为:Thread th = new Thread();
2.Thread(Runnable target),那Runnable是啥,我们看api底层定义
@FunctionalInterface public interface Runnable { //中间一段注释我删了,有兴趣的可以自行通过底层查看 public abstract void run(); }
一目了然,Runnable是一个接口,定义了一个抽象方法run();所以我们在运用时就应该
使用一个实现了Runnable接口的对象我们从api视图可以知道,Thread实现了Runnable
接口,所以最常用的对象一般就是一个Thread的子类
线程使用方法
-
一个类最关键的是如果使用,我们看api手册,给出的方法
1.创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。
2.创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递并启动。
那我们根据手册给出的方法来使用Thread类1.根据第一种方法我们先创立一个子类,这里名字取为sonThread继承Thread
class sonThread extends Thread { //会叫你重写一个run()方法,具体的定义为自己要执行的逻辑代码 //这里我们写一条输出语句随便测试下 @Override public void run() { System.out.println("子线程运行!"); } }
子类写完了,我们在主函数中调用一下,主函数就是主线程,所以一个进程中至少包含一个线程
public static void main(String[] args){ sonThread son = new sonThread(); ~~son.run()~~;//如果直接调用这个方法,那跟普通的程序有什么区别呢? //所以Thread给了一个方法start();调用这个方法才能变成线程运行。 son.start();//这样我们第一个线程调用就完成了 }
2.创建一个子类实现Runnable接口
class sonThread2 implements Runnable{ //也会重写run()方法,我们同样打印一个输出语句 @Override public void run() { System.out.println("子线程2运行!"); } }
同样的,我们在主函数中调用,但是要注意了,我们这时候就要用之前提到的第二种构造器
public static void main(String[] args){ Thread son2 = new Thread(new sonThread2()); son2.start(); }
我们来看看控制台输出:
这样我们第一个多线程就做完了,但是并没有体现出多线程,为了方便观看我们改改代码
我们在第一个函数里面加个for循环 并打印当前i
public static void main(String[] args){
sonThread son = new sonThread();
son.start();
sonThread son3 =new sonThread();
son3.start();
/* Thread son2 = new Thread(new sonThread2());
son2.start();*/
}
我们来看看打印结果:
很直观的就能看出多线程的并发执行,但是现在又引出一个疑问那我们怎么区分是哪个线程?
线程的命名以及获取名字
-
基于上面的问题,我们就想能不能给线程也设置一个名字,这样我们就能区分到底是哪个线程在调用了。
所以Thread的api也给了我们一个方法setName(),以及获取名字的方法getName(),我们来看看具体的使用
我们就在原来的主函数上进行修改son.setName("子程序一号");//另外一个相应的也取个名字,注意这个要放在start()方法前
然后修改一下子线程类里面的打印语句
System.out.println(this.getName()+"子线程运行!"+i);
然后我们再来看看控制台打印结果:
这样就非常明显的能看出多线程,以及是哪个线程在运行了。但是又有一个问题产生了:
这是getName()这个方法是Thread对象才能获取的,如果我们是实现的借口应该怎么弄呢?
于是api也给我们提供了一个相应的方法可以放回一个Thread对象这样就能使用getName(),具体如下:
System.out.println(Thread.currentThread().getName()+"子线程2运行!"+i);
上面这个是修改的借口那个线程类的打印,然后我们再来控制台看看效果:
线程的休眠以及打破睡眠
-
计算机的计算能力现在已经非常强了,所以一秒内,线程执行的次数也非常多,所以我们想要观察某些
线程的运行情况反而十分困难,于是api提供了一个方法sleep(long),参数是时间以毫秒为单位
我们来用代码举个例子,比如我想让线程一不运行这么快,一秒运行一次,我们就可以这样做,
为了更加直观的观看效果,我把一个线程改成打印时间,有兴趣的可以自己试试,下面我们来看代码:class sonThread extends Thread { @Override public void run() { for(int i=0;i<100;i++) { System.out.println(this.getName()+"子线程运行!"+i); try { Thread.sleep(1000);//加入休眠时间1s } catch (InterruptedException e) { e.printStackTrace(); } } } }
能够看出程序按我们想象中的一秒打印一次。