Day21-2
1 Thread类
1.1 获取线程名称
- getName() :
获取线程名称 - 特点:
(1)如果没有给线程设置名称,线程会有一个默认名称
名字:Thread -x(序号从0开始)
(2)在子类对象中可以直接调用该方法,用来打印该线程的名称
代码
package demos2;
public class Demo01 {
public static void main(String[] args) {
// Thread t1 = new Thread();
// System.out.println(t1.getName());
//
// Thread t2 = new Thread();
// System.out.println(t2.getName());
//使用匿名内部类创建子类对象
Thread t3 = new Thread(){
@Override
//在子类类型中,重写父类的run方法,表示需要执行的任务
//因为子类继承了父类的getName方法,所以可以打印名称
//打印的条件是启动线程
public void run(){
System.out.println(getName());
}
};
t3.start();
}
}
1.2 设置线程名称
setName(String name)
:给线程对象设置名称Thread(String name)
:通过构造给线程命名Thread(Runnable target, String name)
:在接收一个任务的同时给线程命名- 注意:
(1)如果想要给子类线程对象命名,可以使用从父类继承的set方法
也可以使用构造方法,但是子类需要自己定义有参构造赋值
代码
package demos2;
public class Demo02 {
public static void main(String[] args) {
Thread t1 = new Thread();
System.out.println(t1.getName());
t1.setName("新线程001");
System.out.println(t1.getName());
Thread t2 = new Thread("新线程002");
System.out.println(t2.getName());
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("新线程执行的任务");
}
};
Thread t3 = new Thread(r,"新线程003");
System.out.println(t3.getName());
}
}
代码2
package demos2;
public class Demo03 {
public static void main(String[] args) {
MyThread2 mt = new MyThread2("新线程");
mt.start();
}
}
//子类定义有参构造,给属性赋值
class MyThread2 extends Thread{
public void run(){
System.out.println(getName());
}
public MyThread2(String name){
super(name);
}
}
1.3 获取线程对象
- 方法:currentThread()
- 特点:
(1)将来哪一个线程执行这个方法,就返回对应的线程对象
(2)是一个静态方法
代码
package demos2;
public class Demo04 {
public static void main(String[] args) {
MyTask mt = new MyTask();
Thread t1 = new Thread(mt,"线程01");
Thread t2 = new Thread(mt,"线程02");
t1.start();
t2.start();
}
}
//类型是用来定义任务
class MyTask implements Runnable{
@Override
public void run() {
System.out.println("新线程需要执行的任务");
//将来哪一个线程执行该任务,就打印对应线程的线程名称
//想要去打印线程名称;通过线程对象.getName();
//哪一条线程执行该方法,就返回对应的线程对象
Thread t = Thread.currentThread();
System.out.println(t.getName());
}
}
1.4 练习
- 获取main线程的线程名称
- 获取垃圾回收线程名称
代码
package demos2;
public class Test01 {
public static void main(String[] args) {
//获取主线程名称
//获取主线程的线程对象
Thread t = Thread.currentThread();
System.out.println(t.getName());
//获取垃圾回收线程的线程名称
//获取垃圾回收线程的线程对象
new Demo();
System.gc();
}
}
class Demo{
//当前类的对象被回收时,会有垃圾回收线程执行该方法
@Override
protected void finalize() throws Throwable {
//该方法是由垃圾线程执行,返回的垃圾线程的对象
Thread t = Thread.currentThread();
//返回垃圾线程的名称
System.out.println(t.getName());
}
}
1.5 线程休眠
- Thread.sleep(long time):让执行这段代码的线程休息一会
参数time:表示线程休息的时间 毫秒为单位 - 特点:
哪一个线程执行该方法,就让对应的线程进行休眠 - 注意事项:
(1)如果在一个普通的方法中,使用sleep(),可以声明异常也可以捕获异常
(2)如果在一个重写的方法中,使用sleep(),只能对该异常进行捕获处理,不能声明
(3)使用该方法,会出现一个编译时异常:InterruptedException 线程中断异常
当线程休眠被中断时,会抛出该异常
(4)interrupt
可以强制唤醒正在休眠的线程(一旦休眠的线程被强制唤醒,会出现线程中断异常)
代码1
package demos2;
public class Demo05 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new MyTask3());
t.start();
}
}
class MyTask3 implements Runnable{
@Override
public void run() {
for(int i = 10;i >= 1;i--){
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
代码2
package demos2;
public class Demo06 {
public static void main(String[] args) throws InterruptedException {
MyTask4 mt = new MyTask4();
Thread t = new Thread(mt);
t.start();
t.sleep(5000);//Thread.sleep();
//哪一个线程执行该方法,就让哪一个线程休眠
//虽然休眠是t线程调用的,但是在主线程中执行的该方法,是主线程休眠
//总结:sleep()方法不是谁调用,谁就休眠
// 谁执行谁休眠
}
}
class MyTask4 implements Runnable{
@Override
public void run() {
for(int i = 10;i >= 1;i--){
System.out.println(i);
}
}
}
代码3
package demos2;
public class Demo07 {
public static void main(String[] args) throws InterruptedException {
MyThread1 mt = new MyThread1();
mt.start();
//在5秒之后,强制唤醒正在休眠的线程(休眠中断)
Thread.sleep(5000);
//强制唤醒线程休眠
mt.interrupt();
}
}
class MyThread1 extends Thread{
@Override
public void run(){
System.out.println("新线程开始执行了.....");
System.out.println("新线程又开始休眠了,预计休眠的时间为:1年...");
try {
Thread.sleep(1000*60*60*24*365);
} catch (InterruptedException e) {
System.out.println("该线程睡觉被意外吵醒了!!!");
}
System.out.println("新线程任务执行结束了...");
}
}
1.6 守护线程
- 概念:保护其他线程能够正常运行的线程就是守护线程。
- 方法
函数名 | Value |
---|---|
setDaemon(boolean on) | 将当前线程对象设置为指定线程,参数为true为守护线程否 则为非守护线程。 |
isDaemon() | 判断当前对象是否是一个守护线程 |
- 注意:
(1)自定义的线程对象都是非守护线程(用户线程)
(2)如果守护线程要保护的用户线程结束了,守护线程会跟着直接结束
(3)如果一个守护线程需要保护多条用户线程,如果多条用户线程全部结束,守护线程才结束,如果多条用户线程有一条是执行的,守护线程不会结束
代码
package demos2;
public class Demo08 {
public static void main(String[] args) {
Thread t1 = new Thread(){
public void run(){
while(true){
System.out.println(getName() + "...正在执行任务");
}
}
};
t1.setName("新线程01");
//将t1线程设置为守护线程
t1.setDaemon(true);
//判断t1线程是否是守护线程
System.out.println(t1.isDaemon());
//启动守护线程,(随着主线程的结束,跟着结束)
t1.start();
}
}
1.7 练习
(1)判断main线程是否是一个守护线程
(2)判断垃圾回收线程是否是一个守护线程
代码
public class Demo01 {
public static void main(String[] args) {
Thread t = Thread.currentThread();
System.out.println(t.isDaemon());
new p();
//强制调用垃圾回收函数
System.gc();
}
}
class p {
@Override
//重写finalize函数,获取垃圾回收线程是否是守护线程
protected void finalize() throws Throwable {
Thread t = Thread.currentThread();
System.out.println(t.isDaemon());
}
}
1.8 设置线程优先级
-
线程优先级概念:
自定义的线程都有一个默认的优先级,默认的优先级都是相同,被cpu执行的机会相同
可以设置线程的优先级,线程优先级高的线程,被cpu先执行机会高
线程优先级低的线程,被cpu先执行的机会低 -
设置优先级的方法:
setPriority(int newPriority) :设置线程优先级
参数:表示优先级的级别:从低到高1 ---- 10
如果不给线程设置优先级:都是默认的:5 -
静态常量:
static int MAX_PRIORITY
线程可以拥有的最大优先级。
static int MIN_PRIORITY
线程可以拥有的最小优先级。
static int NORM_PRIORITY
分配给线程的默认优先级。
代码
package demos2;
public class Demo09 {
public static void main(String[] args) {
Thread t1 = new Thread(){
public void run(){
for(int i = 1;i <= 100;i++){
System.out.println(getName() +"...." + i);
}
}
};
Thread t2 = new Thread(){
public void run(){
for(int i = 1;i <= 100;i++){
System.out.println(getName() +"--------------" + i);
}
}
};
t1.setName("线程01");
t2.setName("线程02");
//设置线程优先级为最低:每一次被cpu执行的概率最小的
t1.setPriority(Thread.MAX_PRIORITY);
//设置线程优先级为最高:每一次被cpu执行的概率最高的
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}