点击链接返回标题->
Java线程的学习-CSDN博客
目录
前言
有关线程名字的成员方法:
String getName()
void setName(String name)
Thread(String name)
获取线程对象的成员方法:
static Thread currentThread()
让线程睡眠的成员方法:
static void sleep(long time) throws InterruptedException
有关线程优先级的成员方法
int getPriority()
void setPriority(int newPriority)
守护线程
void setDaemon(boolean on)
礼让线程
static void yield()
插入线程
void join() throws InterruptedException
前言
在上一篇中学习了多线程的3种实现方式,其实已经不可避免地涉及到了Thread类的部分成员方法,有用setName()方法设置线程名字,用getName()方法获取当前线程名字,以及一个Thread类的静态方法currentThread()可以获取到当前线程的实例化对象。
本篇我们就来系统性地学习、记录一下Thread类中常用的成员方法。
有关线程名字的成员方法:
String getName()
该方法将以String对象返回当前线程的名字。
特殊的,如果未设置线程名,该方法将返回"Thread-number",其中number按线程的实例化顺序从0开始编号自增。
特殊的,main方法执行的进程(即主进程)名字默认为main,下面两张图验证了这个说法——
示例代码:
void setName(String name)
调用该方法时传入String对象,将为当前线程设置名字,前文已经多次涉及。
Thread(String name)
该方法是Thread类的有参构造方法,在实例化线程对象时传入String对象可以直接完成线程名字设置。
需要注意的是!通常我们会通过自定义子类继承Thread类的方式来实现多线程,但子类不会继承父类的构造方法!因此这种情况下必须使用super关键字去调用父类的构造方法。
示例代码:
部分运行结果:
测试代码:
public class Main {public static void main(String[] args) {myThread t1 = new myThread();//实例化对象,线程t1myThread t2 = new myThread("有参构造设置名称");//实例化对象,线程t2并调用有参构造给线程设置名称t1.setName("线程1");//设置线程t1的名字t1.start();//启动线程t1t2.start();//启动线程t2}
}class myThread extends Thread {//自定义子类myThread继承Thread类myThread() {}myThread(String name) {super(name);System.out.print("有参构造被调用");}@Overridepublic void run() {//重写run()方法for (int i = 1; i <= 100; i++) {System.out.println("当前线程名字为:" + getName());}}
}
获取线程对象的成员方法:
static Thread currentThread()
这个方法可以获取当前线程的实例化对象,前面已经多次涉及。
对于主线程main,这里补充了一些细节——
- 当JVM虚拟机启动之后,会自动启动多条线程
- 其中一条线程就叫main线程
- 它的作用就是去调用main方法,并执行里面的代码
- 在以前,我们写的所以代码,其实都是运行在main线程中(没有开多线程)
让线程睡眠的成员方法:
static void sleep(long time) throws InterruptedException
这个方法是Thread的静态方法,它的作用时让当前线程“睡眠”(即暂停运行)time毫秒
注意time的单位是毫秒->1秒(s)等于1000毫秒(ms)
调用该静态方法的方法需要声明抛出InterruptedException异常类或者用try...catch...finally语句处理异常,否则代码无法运行。
示例代码:
public class Main {public static void main(String[] args) throws InterruptedException {System.out.println("第一句话打印完后main线程睡眠7秒");Thread.sleep(7000);System.out.println("然后继续打印第二句话");}
}
上面的示例展示了main进程的睡眠,如果是在新开的自定义进程睡眠的话,有些许不同之处。主要原因在于,在Thread这个父类中没有声明抛出InterruptedException异常类,所以自定义的子类也不能声明抛出异常,解决方法是使用try...catch...finally语句进行异常处理
有关异常类见本篇->Java异常-CSDN博客
示例代码:
部分运行结果:
public class Main {public static void main(String[] args) throws InterruptedException {myThread t1 = new myThread();myThread t2 = new myThread();t1.start();t2.start();}
}class myThread extends Thread {//自定义子类myThread继承Thread类@Overridepublic void run() {//重写run()方法for (int i = 1; i <= 100; i++) {System.out.println("当前线程名字为:" + getName());try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
有关线程优先级的成员方法
在计算机当中,线程的调度有两种方式——
- 抢占式调度:这种方式下,线程完全随机被调度,(假设共3个线程)1完了可能是3,3完了可能是1,接着可能是2,纯靠随机调度(不同线程拥有不同的优先级,优先级越高的线程,被调度的概率越大)。
- 轮流式调度:这种方式下,线程按顺序轮流调度,(假设共3个线程)1完了到2,2完了到3,3完了又回到1。
在Java中,运用的是抢占式调度,线程的优先级共10级,级别越大的线程其优先级越高,抢到cpu执行权的概率越大,被调度的概率越大。
下图展示了Thread类的源码,其中有3个成员变量,分别表示最低级别1、默认级别5、最高级别10。
int getPriority()
这个方法用来获取当前线程的优先级,对于未设置过优先级的线程,优先级默认为5
下图示例代码验证了这个说法——
void setPriority(int newPriority)
这个方法用来设置当前线程的优先级,传入一个1到10之间整数进行设置。
示例代码:
public class Main {public static void main(String[] args) throws InterruptedException {Thread t = Thread.currentThread();//获取当前线程(即主线程)的实例化对象System.out.println("主线程的优先级为:" + t.getPriority());//打印当前线程的优先级myThread myt1 = new myThread();myThread myt2 = new myThread();//自定义两个线程myt1.setName("线程1");myt2.setName("线程2");//设置两个线程的名字myt1.start();myt2.start();//启动两个线程myt1.setPriority(1);myt1.setPriority(10);//分别设置优先级为1和10,显然线程2的优先级更大,被调度的概率更高}
}class myThread extends Thread {//自定义子类myThread继承Thread类@Overridepublic void run() {//重写run()方法for (int i = 1; i <= 100; i++) {System.out.println(getName() + "打印了" + i);}}
}
守护线程
被设置为守护线程的线程将在其它非守护线程执行完毕后,陆续结束执行(注意此处“陆续”的含义,不是立刻结束)
光看定义确实十分抽象,因此举了一个实际应用场景的例子:
如下图是很常见的qq传输文件场景,对于这个聊天页面,可以认为是线程1,对于传送文件这个过程,可以认为是线程2。
在传输过程中,如果你突然关闭了这个聊天窗口(即结束了线程1),这个时候线程2就会跟着一起结束执行,这种关系下线程2就被称为守护线程。
void setDaemon(boolean on)
这个方法用来设置线程为守护线程,传入一个布尔类型的值true,表示将当前线程设置为守护线程。
代码示例——
public class Main {public static void main(String[] args) throws InterruptedException {myThread1 t1 = new myThread1();myThread2 t2 = new myThread2();t1.setName("线程1");t2.setName("线程2");//分别命名t2.setDaemon(true);//将线程2设置为守护线程t1.start();t2.start();}
}class myThread1 extends Thread {//这个线程是非守护线程@Overridepublic void run() {//重写run()方法,打印10次for (int i = 1; i <= 10; i++) {System.out.println(getName() + "打印了" + i);}}
}class myThread2 extends Thread {//这个线程是守护线程@Overridepublic void run() {//重写run()方法,打印100次for (int i = 1; i <= 100; i++) {System.out.println(getName() + "打印了" + i);}}
}
礼让线程
在多线程中常常遇到下图这种情况,连续好几次一直被同一个线程抢占到cpu的执行权(虽说默认优先等级都是5,但耐不住有的线程比较“欧”)
礼让线程的含义就是让当前线程让出当前的cpu执行权,注意,让出执行权之后并不是说执行权就一定给别的线程了,而是让别的线程有更多机会来跟自己抢夺执行权(
我只是给你机会,又没说一定给你是吧),所以说让出执行权后又再次抢到的可能也是存在的!
static void yield()
该静态成员方法用来礼让线程,让出执行权给其它线程更多的执行机会,在一定程度上使执行权均匀分配。
插入线程
void join() throws InterruptedException
该方法用于将当前线程插入到另一线程之前,被插入的线程结束前不会执行它后面的线程。
调用该静态方法的方法需要声明抛出InterruptedException异常类或者用try...catch...finally语句处理异常,否则代码无法运行。
需要注意的是,插入操作必须写在启动操作之后(即先start后join)!