线程Thread类的基本用法

目录

1.线程创建

2.线程中断

3.线程等待

4.线程休眠

 5.获取线程实例


1.线程创建

方法1.继承Thread类:

class MyThread extends Thread{//继承Thread来创建一个线程类
    @Override
    public void run() {
        while(true) {
            System.out.println("hello world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args){
        Thread t = new MyThread();//将MyThread实例化
        t.start();//真正开始创建线程(在操作系统内核中,创建出对应线程的PCB加入到系统链表中,参与调度)
        while(true) {
            System.out.println("hello main");//并发+并行,多个线程的执行程序是无序的,是调度器随机调度
            try {
                Thread.sleep(1000);//线程阻塞,单位为ms
            } catch (InterruptedException e) {
                e.printStackTrace();//阻塞造成的异常信息
            }
        }

    }
}

方法2.实现Runnable接口

因为Runnable接口也有run方法,所以创建线程实例的同时实现Runnable接口可以调用run方法,做到任务的准备与执行分开

class MyRunnable implements Runnable{//创建一个类实现接口

    @Override
    public void run() {
        while (true) {
            System.out.println("hello world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
public class Demo2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();//类的实例化(相当于在准备任务)
        Thread s = new Thread(runnable);//线程的实例化(准备执行)
        System.out.println("main");
        s.start();//新创建的线程开始执行
    }

}

方法3.匿名内部类创建Thread对象

public class Demo6 {
    public static void main(String[] args) {
        Thread t = new Thread() {//此处就是在创建一个匿名的内部类(没有参数)这个类是Thread的子类
//等于继承,方法重写和实例化都在这里完成了
            @Override
            public void run() {
                while (true) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        };
        t.start();
    }

}

方法4.匿名内部类创建Runnable子类对象

public class Demo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {//中间创建了Runnable子类的对象,相当于中间这些就是构造方法的参数
            @Override
            public void run() {
                while(true){
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
        }
    });
t.start();
}}

方法5:lambda表达式创建Runnable子类对象

public class Demo5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{//lambda表达式
            while(true){
                System.out.println("hello tread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        t.start();
    }

}

线程创建还有其他方式, 比如Callable / FutureTask的方式创建,还有线程池的方式创建,至少有7种

需要注意的是:调用start()方法,才算真正在操作系统的底层创建了一个线程

线程的结束:线程的入口方法执行完,就相当于线程执行完了,例如run()或者main()

2.线程中断

目前共有两种方式:

1.利用共享的标记(全局变量);

2.利用interrupt()方法来通知.

第1种方法示例:

    public class Demo11 {
    private static boolean isQuit = false;//设置标志位当学到volatile时需要用此关键字来修饰
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(!isQuit){
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    break;
                }
            }
        });//主线程和新创建的线程其实是同一时刻执行的,所以改变标志位就能退出循环
        //System.out.println(t.getState());
        t.start();
        Thread.sleep(2000);
        System.out.println("hello main");
        isQuit = true;//需要中断时改变标志位




    }
}

2.利用interrupt方法会有两种情况:

1.如果是线程不处于阻塞状态时,使用interrupt会改变标志位;

2.如果是线程处于阻塞状态sleep()时,使用interrupt会让线程内部产生阻塞的办法例如sleep抛出InterruptedException异常执行catch后的语句,这时可以自己控制中断:

一.直接结束执行(break)

二.稍后等一会再结束(sleep或其他收尾工作 再break)

三.不退出(啥都不干,catch执行完后继续执行循环)

而interrupt方法的标志位我们一般用Thread.currentThread().isInterrupted(),默认设为true,表明即将中断

示例:

public class Demo13 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
           while(!Thread.currentThread().isInterrupted()){interrupt的标志位,注意前面有!
               System.out.println("hello Thread");
               try {
                   Thread.sleep(10000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
           }
        });
        t.start();
        System.out.println("hello main");
        Thread.sleep(20000);//这里我故意设置了主线程的休眠时间更长,从而使得创建的线程在interrupt执行时不是处于阻塞的状态,从而得出结果会改变标志位,跳出循环结束,而不会报出程序阻塞时的异常
        t.interrupt();
    }
}

public class Demo13 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
           while(!Thread.currentThread().isInterrupted()){
               System.out.println("hello Thread");
               try {
                   Thread.sleep(10000);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
           }
        });
        t.start();
        Thread.sleep(500);//这里我设置了主线程时间更短,然后就可以认为创建的线程处于阻塞的状态,从而interrupt方法会抛出InterruptException异常,但循环不会结束,需要我们手动设置
        System.out.println("hello main");
        t.interrupt();
    }

3.线程等待

利用join()方法,如果主线程main需要等待创建的新线程t执行完后才能继续执行,这中间可以加入一个t.join()语句,表示main线程要等待t的线程执行完,就是t必须执行完自己的线程,main才能往后

示例:以计时更直观的看出哪个线程的结束

public class Demo13 {

    public static void main(String[] args) {
        int COUNT = 10_000;
        long begin  = System.currentTimeMillis();
        Thread t1 = new Thread(()-> {
            int a = 0;
            for (long i = 0; i < COUNT; i++) {
                a++;
            }
        });
        Thread t2 = new Thread(()->{
         int b = 0;
         for (long i = 0; i < COUNT; i++){
             b++;
         }
        });
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
            System.out.println("t1.t2运行结束");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("main运行");
        System.out.println("运行时间:"+(end - begin) + "ms");

        }

    }

此处的意思是需要等到t1.t2线程都运行完了之后main线程才能结束

总结就是想让谁阻塞,谁就调用join.

调用t1.join,main会在t1.join这个语句中阻塞,等待t1完成后再往下走

4.线程休眠

public static void sleep(long millis) throws InterruptedException休眠当前线程 millis
毫秒
public static void sleep(long millis, int nanos) throws
InterruptedException
可以更高精度的休眠
public static void main(String[] args) throws InterruptedException {
            long a = System.currentTimeMillis();
            Thread.sleep(3 * 1000);
            long b = System.currentTimeMillis();
            System.out.println("休眠时间为:"+(b-a));
        }

 5.获取线程实例

线程在Java有个专门的类Thread,里面有其成员属性,成员方法以及构造方法

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

当我们创建了一个线程类对象时,可以利用获取的方法得到线程对象里面的信息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值