多线程中常用的方法

线程的终止stop

  • 不使用JDK提供的stop方法/destroy方法(它们本身也被JDK给废弃了)
  • 现在提供了一个boolean型的终止变量,当这个变量置为false,则线程就终止运行。
  • 终止线程的方式
    1. 线程运行完毕正常终止。
    2. 外部干涉线程终止--->需要加入标识
    3. 不要使用stop和destroy这样过时的不安全的线程终止方法

示例

public class ThreadStop implements Runnable{
    private String name;
    //加入标识 标记线程是否可以运行
    private boolean flag=true;

    public ThreadStop(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        int i=0;
        //线程的终止取决于flag的状态
        while (flag){
            System.out.print("\t"+name+"---"+i++);
        }
    }
    //对外提供方法改变标识
    public void terminate(){
        this.flag=false;
    }

    public static void main(String[] args) {
        ThreadStop t=new ThreadStop("李清照");
        new Thread(t).start();
        for (int i = 0; i < 20; i++) {
            if(i==10){
                //外部控制线程的终止
                t.terminate();
                System.out.println();
                System.out.println("t is game over");
            }
            System.out.print("main\t"+i);
        }
    }
}

线程的暂停 sleep

  • sleep方法:指定当前线程阻塞的毫秒数(1000毫秒==1秒)
  • sleep存在异常InterruptedException
  • sleep指定的时间过去后,线程进入就绪状态。
  • sleep可以用来模拟网络延时,倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁

示例一:倒计时

public class ThreadSleep01 {
    public static void main(String[] args) {
        try {
            countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //模拟倒计时
    public static void countDown() throws InterruptedException {
        int num = 10;//10秒
        while (true) {
            Thread.sleep(1000);
            System.out.println(num--);
            if (num <= 0) {
                break;
            }
        }
    }
}

示例二:每一秒获取一次当前时间

public class ThreadSleep02 {
    public static void main(String[] args) {
        //获取系统当前时间
        Date startTime = new Date(System.currentTimeMillis());
        while (true) {
            try {
                Thread.sleep(1000);
                //更新系统时间
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程的礼让 yield

  • 线程的礼让就是让当前正在执行的线程暂停。
  • 不是阻塞线程,而是将线程的运行状态转入就绪状态。让cpu调度器重新调度。
  • 礼让不一定成功,因为礼让后任然为就绪状态,还是会进行竞争cpu资源。
  • 写在那个线程体中那个线程就进行礼让。

示例

public class ThreadYield01 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("yield"+i);
        }
    }
    public static void main(String[] args) {
        ThreadYield01 yield01=new ThreadYield01();
        new Thread(yield01).start();
        for (int i = 0; i < 100; i++) {
            if(i%20==0){
                //主线程进行礼让
                Thread.yield();
            }
            System.out.println("main"+i);
        }
    }
}
//礼让就是让线程从运行状态到就绪状态
//上面的程序是在主线程中每当i是20的倍数就礼让上面run方法中的线程。
//但是礼让不一定成功,因为线程的调度不是人为的,而是cup的调度决定的。

线程的合并join

  • join合并线程,待此线程执行完成后,再执行其它的线程。其它的线程就处于阻塞状态
  • 可以理解为线程的插队,当一辆车(线程)插队后,被插队的车辆(其它线程)就只能让插队车辆先行,因为被插队,所以在插队的过程中,被插队的车辆处于阻塞的状态(线程阻塞),当插队完成(线程执行完毕),其它车辆继续驾驶(执行其它线程)。
  • 写在那个线程体中那个线程就被阻塞了。

示例

package com.cn.Callable;

public class ThreadJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("线程vip" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //启动我们的线程
        ThreadJoin joinThread = new ThreadJoin();
        Thread thread = new Thread(joinThread);
        thread.start();

        //主线程
        for (int i = 0; i < 20; i++) {
            if (i == 5) {
                thread.join();//插队(main线程被插队)
            }
            System.out.println("main" + i);
        }
    }
}

获取线程的状态 getState

线程状态。线程可以处于以下状态之一:

  • NEW:尚未启动的线程处于此状态。
  • RUNNABLE:在Java虚拟机中执行的线程处于此状态。
  • BLOCKED:被阻塞等待监视器锁定的线程处于此状态。
  • WAITING:没有时间限制地等待其他线程执行特定操作。
    • object.wait()
    • thread.join()
    • LockSupport.park()
  • TIMED_WAITING:在指定时间段内等待其他线程执行特定操作。
    • thread.sleep(long millis)
    • wait(int timeout) or wait(int timeout, int nanos)
    • thread.join(long millis)
    • LockSupport.parkNanos
    • LockSupport.parkUntil
  • TERMINATED:已退出的线程处于此状态。

示例

public class ThreadState {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("run方法执行中");
        });
        //观察线程启动前 NEW
        Thread.State state = thread.getState();
        System.out.println(state);
        //观察启动后 RUNNABLE
        thread.start();
        state = thread.getState();
        System.out.println(state);
        while (state != Thread.State.TERMINATED) {//只要现成不终止,就一直输出状态
            Thread.sleep(100);
            state = thread.getState();//更新线程状态
            System.out.println(state);
        }
        //死亡后的线程不能再启动了,启动会报异常
        //thread.start();
    }
}

线程优先级 setPriority getPriority()

  • java提供一个线程调度器来监控程序启动后进入就绪状态的所有线程,线程调度器按照线程的优先级决定应调度那个线程来执行。
  • 优先级的设定建议在start()调用前。
  • 优先级低只意味获得调度的概率低,并不是绝对先调用优先级高的线程,后调用优先级低的线程。
  • 线程的优先级是从1到10
    1. NORM_PRIORITY 5
    2. MIN-PRIORITY 1
    3. MAX-PRIORITY 10
  • 所有的线程的优先级都默认是5

示例

public class ThreadPriority {
    public static void main(String[] args) {
        //主线程默认优先级为5 不可更改
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();
        Thread thread1 = new Thread(myPriority);
        Thread thread2 = new Thread(myPriority);
        Thread thread3 = new Thread(myPriority);
        Thread thread4 = new Thread(myPriority);
        Thread thread5 = new Thread(myPriority);

        //先设置优先级,再启动
        thread1.start();

        thread2.setPriority(1);
        thread2.start();

        thread3.setPriority(4);
        thread3.start();

        thread4.setPriority(Thread.MAX_PRIORITY);//MAX_PRIORITY=10
        thread4.start();

        thread5.setPriority(8);
        thread5.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

设置线程为守护线程 setDaemon

  • 线程分为守护线程和用户线程。
  • 虚拟机必须确定用户线程执行完成,不用等待守护线程是否执行完毕。
  • 使用场景:后台记录操作日志,监控内存,垃圾回收等

示例 上帝守护你

public class ThreadDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread thread = new Thread(god);
        //默认false表示是用户线程,正常的线程都是用户线程
        thread.setDaemon(true);
        //上帝守护线程启动
        thread.start();
        //你 用户线程启动
        new Thread(you).start();
    }
}

//上帝
class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("上帝保佑着你");
        }
    }
}

//你
class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("你一生都开心的活着");
        }
        System.out.println("====goodbye!world====");
    }
}
//结果我们发现用户线程执行完毕后一段时间,我们发现守护线程也结束执行。
//守护线程我们没有设置结束条件,为啥还是结束了呢?
//这是因为虚拟机并不会等待守护线程执行结束。守护线程服务于用户线程

参考教程:狂神学java

posted @ 2021-04-19 16:35  懒鑫人  阅读(82)  评论(0)    收藏  举报