java基础(多线程)-常用方法具体使用

一、Thread.start()方法

start()方法:启动子线程

new Thread();当前线程的状态为NEW

调用start()方法之后当前线程的状态变为RUNNABLE

二、Thread.sleep()静态方法

1. 调用sleep会让当前线程从Running进入Timed Waiting 状态

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

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

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

总结:在没有利用CPU来计算时,不要让while(true)空转cpu,这时可以使用yield或sleep来让出cpu的使用权给其他程序

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

三、yield()

1. 调用yield会让当前线程从Running进入Runnable就绪状态,然后调度执行其他线程

2. 具体的实现依赖于操作系统的任务调度器。

四、线程优先级setPriority

  • 线程优先级会提示调度器优先调度该线程,但它仅仅是提示,调度器可以忽略它
  • 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没作用。

五、join() 等待线程结束

  • 需要等待结果返回,才能继续运行就是同步
  • 不需要等待结果返回,就能继续运行就是异步

六、interrupt()方法

interrupt打断sleep,wait,join的线程。叫醒线程。

七、两阶段终止模式

如何终止一个线程
终止一个线程早期Thread是提供对应的停止方法的,比如stop等,但是到后来停止一个线程的api都已经过时了,即存在风险,不推荐使用,那如果碰到这种线程停止的需求如何实现, 且是优雅的实现, 那么两个阶段终止模式就可以实现。它的意思就是, 第一阶段时准备停止阶段,第二阶段是停止阶段。思路就是 B线提供一个一个标志,如果别的线程把这个标志设计为true,那么当前线程就终止。

java基础(多线程)-常用方法具体使用_第1张图片
 

class TwoPhaseTermination{
    Logger logger =LoggerFactory.getLogger(TwoPhaseTermination.class);
    private Thread monitor;
    //启动监控线程
    public void start(){
        monitor = new Thread(()->{
            while (true){
                Thread current = Thread.currentThread();
                if(current.isInterrupted()){
                    logger.info("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);
                    logger.info("执行监控记录");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //重新设置打断标记
                    monitor.interrupt();
                }
            }
        });
        monitor.start();
    }

    public void stop(){
        monitor.interrupt();
    }
}

八、不推荐使用方法

还有一些不推荐使用的方法,这些方法已过时,容易破坏同步代码块,造成线程死锁

方法名 static 功能说明
stop() 停止线程运行
suspend() 挂起(暂停)线程运行
resume() 回复线程运行

九、主线程与守护线程

默认情况下,Java进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。

    public void testDaemon() throws InterruptedException {
        logger.info("开始运行...");
        Thread t1 = new Thread(() -> {
            logger.info("开始运行...");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            logger.info("运行结束...");
        },"daemon");
        //设置该线程为守护线程
        t1.setDaemon(true);
        t1.start();
        Thread.sleep(1000);
        logger.info("运行结束...");
    }
  • 垃圾回收器线程就是一种守护线程
  • Tomcat中的Acceptor和Poller线程都是守护线程,所以Tomcat接收到shutdown命令后,不会等待他们处理完当前请求。

十、线程的五种状态

从操作系统层面来描述,线程有五种状态

java基础(多线程)-常用方法具体使用_第2张图片

【初始状态】:仅是在语言层面创建了线程对象,还未与操作系统线程关联

【可运行状态】:(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由CPU调度执行

【运行状态】:指获取了CPU时间片运行中的状态

  • 当CPU时间片用完,会从【运行状态】转换至【可运行状态】 ,会导致线程的上下文切换。

【阻塞状态】:

  • 如果调用了阻塞API,如BIO读写文件,这时该线程实际不会用到CPU,会导致线程上下文切换,进入【阻塞状态】
  • 等BIO操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】
  • 与【可运行状态】的区别是,对【阻塞状态】的线程来说,只要他们一直不唤醒,调度器就一直不会考虑调度他们。

【终止状态】:表示线程已经执行完毕,生命周期已经结束,不会再转换为其他状态。

十一、线程的六种状态

六种状态是从Java API层面来描述,根据Thread.state枚举,分为六种状态。

java基础(多线程)-常用方法具体使用_第3张图片

 【NEW】:线程刚被创建,但是还没有调用start()方法

【RUNNABLE】:当调用了start()方法之后,注意Java API层面的RUNNABLE状态涵盖了操作系统层面的【可运行状态】、【运行状态】和【阻塞状态】(由于BIO导致的线程阻塞,在java里无法区分,仍然认为是可运行)

【BLOCKED、WAITING、TIMED_WAITING】三种状态都是java api层面对【阻塞状态】的戏份,后面会在状态转换一节详细讲述。

【TERMINATED】:当线程代码运行结束

public void testThreadState() throws InterruptedException {
        Thread t1 = new Thread("t1"){
            @Override
            public void run(){
               logger.info("running...");
            }
        };

        Thread t2 = new Thread("t2"){
            @Override
            public void run(){
                while (true){

                }
            }
        };
        t2.start();


        Thread t3 = new Thread("t3"){
            @Override
            public void run(){
                logger.info("running...");
            }
        };
        t3.start();

        Thread t4 = new Thread("t4"){
            @Override
            public void run(){
                synchronized (ThreadTest.class){
                    try {
                        Thread.sleep(100000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        };
        t4.start();

        Thread t5 = new Thread("t5"){
            @Override
            public void run(){
                try {
                    t2.join();
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        };
        t5.start();

        Thread t6 = new Thread("t6"){
            @Override
            public void run(){
                synchronized (ThreadTest.class){
                    try {
                        Thread.sleep(100000);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        };
        t6.start();
        Thread.sleep(500);
        logger.info("t1的状态{}",t1.getState()); //NEW
        logger.info("t2的状态{}",t2.getState()); //RUNNABLE
        logger.info("t3的状态{}",t3.getState()); //TERMINATED
        logger.info("t4的状态{}",t4.getState()); //TIMED_WAITING
        logger.info("t5的状态{}",t5.getState()); //WAITING
        logger.info("t6的状态{}",t6.getState()); //BLOCKED
    }

你可能感兴趣的:(java,开发语言,jvm)