JUC线程常用方法

线程常用方法介绍

1、方法概述

方法说明static功能说明注意
start()启动一个新线程,
在新的线程运行
run方法中的代码
start方法只是让线程进入就绪,里面代码不一定立刻运行
(CPU的时间片还没分给它)。每个线程对象的start方法只
能调用一次,如果调用了多次会出现
IllegalThreadStateException
run()新线程启动后会调
用的方法
如果在构造Thread对象时传递了Runnable参数,则线程启
动后会调用Runnable中的run方法,否则默认不执行任何操
作。但可以创建Thread的子类对象,来覆盖默认行为
join()等待线程运行结束
join(long n)等待线程运行结束,
最多等待n毫秒
getId()获取线程idid唯一
getName()获取线程名
setName(String)修改线程名
getPriority()获取线程优先级
setPriority(int)修改线程优先java中规定线程优先级是1~10的整数,默认是5,较大的优先级
能提高该线程被CPU调度的机率
getState()获取线程状态Java中线程状态是用6个enum表示,分别为:NEW
RUNNABLE、BLOCKED、WAITING、TIMED_WAITING.
TERMINATED
isInterrupted()判断是否被打断,不会清除打断标记
isAlive()线程是否存活
(还 没有运行完毕)
interrupt()打断线程如果被打断线程正在sleep,wait,join会导致被打断的线程
抛出InterruptedException,并清除打断标记;如果打断的正
在运行的线程,则会设置打断标记;park的线程被打断,也
会设置打断标记
interrupted()static判断当前线程是否
被打断
会清除打断标记
currentThread()static获取当前正在执行
的线程
sleep(long n)static让当前执行的线程
休眠n毫秒,休眠时
让出cpu的时间片
给其它线程
yield()static提示线程调度器让
出当前线程对CPU
的使用
主要是为了测试调试

2、start() vc run()

start方法会启动一个线程,并执行实现的run方法,多次执行会抛异常:IllegalThreadStateException

单独调用run方法,会当作main线程中的一个普通线程

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            log.debug("hello world");
        }, "t");

        t.run();
        t.start();
        t.start();//start()方法多次启动会抛异常IllegalThreadStateException
    }

在这里插入图片描述

3、sleep vs yield

1、sleep

1.调用sleep会让当前线程从Runnable进入Timed_Waiting状态

2.其它线程可以使用interrupt方法打断正在睡眠的线程,这时sleep方法会抛出InterruptedException

3.睡眠结束后的线程未必会立刻得到快行

4.建议用TimeUnit的sleep代替Thread的sleep来获得更好的可读性

2、yield

1.调用yield会上当前线程从Running进入Runnable状态,然后调度执行其它同优先级的线程。如果这时没
有同优先级的线程,那么不能保证让当前线程暂停的效果
2.具体的实现依赖于操作系统的任务调度器

3、线程优先级

  • 线程优先级会提示(hit)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它

  • 如果CPU比较忙,那么优先级高的线程会获得更多的时间片,但CPU闲时,优先级几乎没作用

  • 优先级1-10,默认为5

4、示例

打断正在sleep、wait、join的线程,清楚打断标记,并抛出异常

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            try {
                log.debug("run...");
                TimeUnit.SECONDS.sleep(1);//还是使用了Thread.sleep(),线程执行1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t");
        t.start();

        log.debug("state1:{}", t.getState());
        try {
            Thread.sleep(500);//线程执行0.5秒,不停顿,容易导致t线程还没开始执行执行下面的语句:t.getState()等等,结果会不准确
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("state2:{}", t.getState());

        //打断正在sleep、wait、join的线程,清楚打断标记
        log.debug("interrupt...");
        t.interrupt();
        log.debug("打断标记:{}", t.isInterrupted());
    }

在这里插入图片描述

yield会让出CPU,测试优先级和yield

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            int count = 0;
            while (true) {
                Thread.yield();
                System.out.println("t1 ---->" + count++);
            }
        });

        Thread t2 = new Thread(() -> {
            int count = 0;
            while (true) {
                System.out.println("        t2 ---->" + count++);
            }
        });

//        t1.setPriority(Thread.MIN_PRIORITY);//优先级1
//        t2.setPriority(Thread.MAX_PRIORITY);//优先级10
        t1.start();
        t2.start();
    }

使用yield

在这里插入图片描述

使用优先级(注释 Thread.yield()😉,设置t1、t2的优先级
在这里插入图片描述

5、sleep防止CPU占用100%

CPU浪费(一核CPU的Linux)

public class Methods {
    public static void main(String[] args) {
        new Thread(() -> {
            while (true) {
                //try {Thread.sleep(1);} catch (InterruptedException e) {}
            }
        }).start();
    }
}

在这里插入图片描述

去掉注释,使用sleep避免while(true)空转浪费CPU

在这里插入图片描述

  • 可以用wt或条件变量达到类似的效果
  • 不同的是,后两种都需要加锁,并且需要相应的唤醒操作,一般适用于要进行同步的场景
  • sleep适用于无需锁同步的场景

4、join

join,相当于插队,必须等该线程执行完,当前线程才能继续向下执行

示例,main线程需要t线程来计算结果,如果不等t线程计算完,就输出结果,会导致结果不正确

    static int result = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            try {
                log.debug("开始计算...");

                Thread.sleep(1000);
                result = 10;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("计算完成...");
        }, "t");

        t.start();

        //t.join();
        log.debug("结果:{}", result);
    }

在这里插入图片描述

加入t.join()

在这里插入图片描述

使用join(long millis),超时了不会抛出异常

5、interrupt

1、打断阻塞线程

打断阻塞线程,会清楚打断标记(标记线程是否被打断过)

public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(() -> {
        log.debug("hi");
        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }, "t");
    t.start();

    TimeUnit.MILLISECONDS.sleep(500);//相当于Thread.sleep(long millis);
    log.debug("开始打断...");
    t.interrupt();
    log.debug("打断标记  {}", t.isInterrupted());
}

在这里插入图片描述

2、打断运行

打断运行中的线程,打断标记为true

public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(() -> {
        while (true) {
            boolean interrupted = Thread.currentThread().isInterrupted();
            if (interrupted) {
                log.debug("打断运行,推出循环");
                break;
            }
        }
    }, "t");
    t.start();

    log.debug("开始打断...");
    t.interrupt();
    log.debug("打断标记  {}", t.isInterrupted());
}

在这里插入图片描述

6、两阶段终止模式

Two Phase Termination
在一个线程t1中如何优雅终止线程t2?这里的【优推】指的是给t2一个料理后事的机会。

1.错误思路

  • 使用线程对象的stop()方法停止线程,

    stop方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁

  • 使用System.exit(int)方法停I止线程

    目的仅是停止一个线程,但这种做法会让整个程序都停止

2、思路

无异常
有异常
while(true)
有没有被打断
料理后事
结束循环
睡眠2秒
执行监控记录
设置打断标记

3、示例

如果被打断线程正在sleep,wait,join会导致被打断的线程抛出InterruptedException,并清除打断标记;如果打断的正在运行的线程,则会设置打断标记;park的线程被打断,也会设置打断标记

public static void main(String[] args) throws InterruptedException {
    TwoPhaseTermination t = new TwoPhaseTermination();
    t.start();

    Thread.sleep(3500);
    t.stop();
}

static class TwoPhaseTermination{
    private Thread monitor;

    //启动监控现场
    public void start(){
        monitor = new Thread(() -> {
            while (true){
                boolean interrupted = Thread.currentThread().isInterrupted();
                if(interrupted){
                    log.debug("线程终止,料理后事");
                    break;
                }

                try {
                    log.debug("监控记录");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    //重新设置打断标记,因为打断的是sleep中的线程,会清楚打断标记
                    //没有该语句打断后会继续打印 监控记录
                    monitor.interrupt();
                    e.printStackTrace();
                }
            }
        }, "monitor");

        monitor.start();
    }

    //停止监控线程
    public void stop(){
        monitor.interrupt();
    }
}

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值