Java--多线程之join,yield,sleep;线程优先级;定时器;守护线程

Posted MinggeQingchun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java--多线程之join,yield,sleep;线程优先级;定时器;守护线程相关的知识,希望对你有一定的参考价值。

Java--多线程之并发,并行,进程,线程(一)_MinggeQingchun的博客-CSDN博客

Java--多线程之终止/中断线程(二)_MinggeQingchun的博客-CSDN博客_java中断线程

Java--多线程之synchronized和lock;死锁(四)_MinggeQingchun的博客-CSDN博客

Java--多线程之生产者消费者模式;线程池ExecutorService(五)_MinggeQingchun的博客-CSDN博客  

一、线程常用方法

/**
1、获取当前线程对象
    Thread t = Thread.currentThread();
2、获取线程对象的名字
    String name = 线程对象.getName();
3、修改线程对象的名字
    线程对象.setName("线程名字");
4、当线程没有设置名字的时候,默认的名字
    Thread-0
    Thread-1
    .....
 */
public class ThreadMethod 
    public static void main(String[] args) 
        //获取当前线程对象,currentThread()
        Thread t = Thread.currentThread();
 
        //获取线程名字"main",getName()
        System.out.println(t.getName());
 
        Thread t1 = new Thread();
        Thread t2 = new Thread();
        //线程默认名字:Thread-0;Thread-1
        System.out.println(t1.getName());//Thread-0
        System.out.println(t2.getName());//Thread-1
 
        //设置线程名字,setName()
        t1.setName("t1");
        System.out.println(t1.getName());//t1
    

二、join

join()方法是Thread 类中的一个方法,它的作用是将当前线程挂起,等待其他线程结束后再执行当前线程,即当前线程等待另一个调用join()方法的线程执行结束后再往下执行

通常用于在main主线程内,等待其它调用join()方法的线程执行结束再继续执行main主线程

/**
 * void join()
 * 合并线程
 * */
public class ThreadJoin 
    public static void main(String[] args) 
        System.out.println("main begin");

        Thread t = new Thread(new Runnable() 
            @Override
            public void run() 
                for(int i = 0; i < 100; i++)
                    System.out.println(Thread.currentThread().getName() + "--->" + i);
                
            
        );
        t.setName("t");
        t.start();

        try 
            t.join();// 当前主线程进入阻塞,t线程执行,直到t线程结束;当前线程才可以继续执行
         catch (InterruptedException e) 
            e.printStackTrace();
        

        System.out.println("main over");
    

三、yield

yield()方法的作用是放弃当前的cpu的资源,将他让给其他的任务去占用cpu执行时间。 但是放弃的时间不确定,有可能刚刚放弃又马上获得cpu时间片

yield()的作用是让步。它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到“运行状态”继续运行!

/**
 * static void yield()  让位方法
 * 静态方法:Thread.yield();
 *
 * 暂停当前正在执行的线程对象,并执行其他线程
 * yield()方法不是阻塞方法。让当前线程让位,让给其它线程使用
 * yield()方法的执行会让当前线程从“运行状态”回到“就绪状态”
 * 注:在回到就绪之后,有可能还会再次抢到
 * */
public class ThreadYeild 
    public static void main(String[] args) 
        Thread t = new Thread(new Runnable() 
            @Override
            public void run() 
                for (int i = 1;i < 10000;i++)
                    System.out.println(Thread.currentThread().getName() + "---->" + i);

                    if (i % 100 == 0)
                        Thread.yield();
                    
                
            
        );
        t.setName("t");
        t.start();

        for (int i = 1;i < 10000;i++)
            System.out.println(Thread.currentThread().getName() + "---->" + i);
        
    

四、sleep

线程sleep方法: static void sleep(long millis)

1、静态方法:Thread.sleep(1000);参数是毫秒

2、作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其它线程使用

3、Thread.sleep()方法,可以做到间隔特定的时间,去执行一段特定的代码,每隔多久执行一次

/**
线程sleep方法:
    static void sleep(long millis)
    1、静态方法:Thread.sleep(1000);参数是毫秒
    2、作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其它线程使用
    3、Thread.sleep()方法,可以做到间隔特定的时间,去执行一段特定的代码,每隔多久执行一次
 */
public class ThreadSleepTest 
    public static void main(String[] args) 

        //让当前主线程进入休眠,睡眠2秒
        try 
            Thread.sleep(1000 * 2);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        System.out.println("hello world");

        for(int i = 0; i < 10; i++)
            System.out.println(Thread.currentThread().getName() + "--->" + i);

            // 睡眠1秒
            try 
                Thread.sleep(1000);
             catch (InterruptedException e) 
                e.printStackTrace();
            
        

        Thread t = new Thread(new Runnable() 
            @Override
            public void run() 
                for(int i = 0; i < 10000; i++)
                    System.out.println(Thread.currentThread().getName() + "--->" + i);
                
            
        );
        t.start();

        try 
            /**
             * 这里虽然是分支线程 t 调用sleep()方法,但是在执行时还是会转换成:Thread.sleep(1000 * 5);
             * 因此会让当前主线程main进入休眠
             * */
            t.sleep(1000 * 5);
         catch (InterruptedException e) 
            e.printStackTrace();
        

        System.out.println("Hello,我睡醒了");
    

五、线程优先级

1、线程调度模型

(1)抢占式调度模型:

哪个线程的优先级比较高,抢到的CPU时间片的概率就高一些/多一些

java采用的就是抢占式调度模型

(2)均分式调度模型:

平均分配CPU时间片。每个线程占有的CPU时间片时间长度一样

2、线程调度方法

实例方法:

void setPriority(int newPriority) 设置线程的优先级int getPriority() 获取线程优先级

最低优先级1;默认优先级是5;最高优先级10

优先级比较高的获取CPU时间片可能会多一些。(但也不完全是,大概率是多的。)

/**
 * 线程优先级
 *
 * void setPriority(int newPriority)    设置线程的优先级
 * int getPriority()                    获取线程优先级
 *
 * 最低优先级1;默认优先级是5;最高优先级10
 *
 * */
public class ThreadPriority 
    public static void main(String[] args) 
        System.out.println("线程最高优先级:"+Thread.MAX_PRIORITY);//10
        System.out.println("线程最低优先级:"+Thread.MIN_PRIORITY);//1
        System.out.println("线程默认优先级:"+Thread.NORM_PRIORITY);//5

        //线程默认优先级
        System.out.println(Thread.currentThread().getName() + "线程的默认优先级是:" + Thread.currentThread().getPriority());

        Thread t = new Thread(new Runnable() 
            @Override
            public void run() 
                for(int i = 0; i < 10000; i++)
                    System.out.println(Thread.currentThread().getName() + "-->" + i);
                
            
        );
        t.setName("t");
        t.setPriority(10);
        t.start();

        Thread.currentThread().setPriority(1);

        // 优先级较高的,只是抢到的CPU时间片相对多一些。
        // 大概率方向更偏向于优先级比较高的。
        for(int i = 0; i < 10000; i++)
            System.out.println(Thread.currentThread().getName() + "-->" + i);
        
    

六、timer定时器

Timer类和TimerTask类

Timer定时器主要用于做 定时任务 或者 按照一定的时间间隔做循环任务

java.util.Timer作为定时器,用于启动定时任务。

java.util.TimerTask实现了 Runnable 接口,需要重写**run()**方法,用于存放我们要做的任务

1、一个Timer定时器只会开启一个新线程

2、一个Timer定时器可以开启多个TimerTask定时任务,但这些任务只是在同一个线程下轮流执行的

/**
 使用定时器指定定时任务
 */
public class TimerTest 
    public static void main(String[] args) 
        Timer timer = new Timer();

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        df.format(date);

        //timer.schedule(定时任务, 第一次执行时间, 间隔多久执行一次);
        timer.schedule(new MyTimerTask(), date,1000);
    


//定时任务类
class MyTimerTask extends TimerTask

    @Override
    public void run() 
        //需要执行的任务
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        System.out.println(df.format(date) + "完成数据备份");
    

七、守护线程

Java语言中线程分为两大类:

1、用户线程

2、守护线程(即 Daemon thread,后台线程)是个服务线程,用来服务于用户线程

其中具有代表性的就是:垃圾回收线程(守护线程)

守护线程的特点: 一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束

在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出

存在任意一个用户线程的时候,JVM就不会退出

JDK 官方文档中有如下一段话

The Java Virtual Machine exits when the only threads running are all daemon threads.

当 JVM 中不存在任何一个正在运行的非守护线程时,则 JVM 进程即会退出

注:

1、主线程main方法是一个用户线程

2、thread.setDaemon(true) 必须在 thread.start() 之前设置,否则会抛出 IllegalThreadStateException 异常

/**
 守护线程

 Java语言中线程分为两大类:
    一类是:用户线程
    一类是:守护线程(后台线程)
    其中具有代表性的就是:垃圾回收线程(守护线程)

 守护线程的特点:
    一般守护线程是一个死循环,所有的用户线程只要结束,守护线程自动结束

 注:主线程main方法是一个用户线程

 守护线程使用场景
    每天00:00的时候系统数据自动备份数据
 * */

public class DaemonThreadTest 
    public static void main(String[] args) 
        DamenThread t = new DamenThread();
        t.setName("t");

        // setDaemon(true)将t设置为守护线程
        t.setDaemon(true);

        t.start();

        for (int i = 1;i <= 10;i++ )
            System.out.println(Thread.currentThread().getName() + "---->" + i);
            try 
                Thread.sleep(1000);
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    


class DamenThread extends Thread
    private int i = 1;

    @Override
    public void run() 
        // 死循环,但由于该线程是守护线程,当用户线程结束,守护线程自动终止
        while (true)
            System.out.println(Thread.currentThread().getName() + "---->" + (i++));
            try 
                Thread.sleep(1000);
             catch (InterruptedException e) 
                e.printStackTrace();
            
        
    

以上是关于Java--多线程之join,yield,sleep;线程优先级;定时器;守护线程的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程之sleep,wait,join和yield关键字,以及线程的关闭

Java多线程系列---“基础篇”14之 wait,sleep,join,yield,park,unpark,notify等通信机制对比

java多线程sleep()yield()wait()join()的区别

Java并发之wait notify yield sleep join

Java线程中yield与join方法的区别

Java多线程学习笔记— “Thread类三个方法:线程休眠sleep()线程礼让yield()线程强制执行join()”