【Java_EE】线程的属性和方法

无论是自己定义的线程还是jvm内部创建的线程,核心在于制定一个任务给线程,让线程知道接下来要做什么任务。

制定任务的方式一般是:重写run/使用runnable/使用lambda...

这是上一节内容(线程的创建方法)

  关于线程属性的设置都要放在start之前设置,一旦线程已经启动,就没法再设置线程属性。(开弓没有回头箭)

1、isDaemon():是否为后台线程

区分前后台线程

前台线程:前台线程不结束,Java进程一定不结束;一个进程中的所有前台线程结束,进程才会结束。

后台线程(守护线程):后台线程继续执行,也不能阻止进程结束。

/**
 *  关于线程属性的设置都要放在start之前设置,一旦线程已经启动,就没法再设置线程属性。(开弓没有回头箭)
 *
 *  // 线程属性
 *     1、getId():获取id,此处的线程id是jvm自己弄得一套id体系和系统中pcb上的id是不同的。Java代码也无法获取到pcb中的id。
 *     2、getName():名称
 *     3、getState():状态
 *     4、getPriority():优先级
 *     5、isDaemon():是否为后台线程
 *                   前台线程:前台线程不结束,那么Java进程一定不会结束。一个进程中所有前台线程结束,进程才会结束。
 *                   后台线程(daemon):后台线程(守护线程)继续执行,也不能阻止Java进程结束。(在jconsole中看到的jvm中包含一些其他的内置线程,就属于后台线程)
 *                   gc(垃圾回收):是周期性持续性执行的线程,不可能主动结束,所以一般设置为后台线程。
 *                   gc线程和main线程同属于同一个进程中。进程结束,则所有线程结束。
 *     6、isAlive():是否存活
 *                  此处的属性:指的是系统中的线程(PCB)是否还存在。
 *                            Thread对象的生命周期 和 PCB的生命周期 是不一定一样的。
 *     7、isInterrupted():是否被终止
 *                        终止线程,在Java中都只是提醒建议,真正要不要终止需要线程本身来决定是否要终止。
 */
public class thread_attribute {
    public static void main(String[] args) {
        // 使用lambda创建一个线程
        Thread thread = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("前台线程:线程结束,进程结束");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        // 此时thread默认是前台线程,thread执行完才结束进程。

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("设置为后台线程:无论线程是否结束,都无法阻止进程结束。进程结束,线程就强行结束。");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        // 此处将线程设置为后台线程
        thread1.setDaemon(true);
        thread1.start();
    }
}

2、isInterrupted():是否被终止

终止线程:在Java中都只是提醒建议,是否要终止线程由当前程序员编写代码是否终止。

以下代码是自己写的一个控制终止线程,写这个段代码是遇到了一些问题!

自定义变量终止线程代码

/**
 *  线程的核心操作
 *  1、start:执行start方法,才是真正将线程创建出来,并执行线程。
 *           每个线程都是独立调度执行的,相当于整个程序中多了一个执行流。
 *           一个Thread对象只能start一次。
 *  2、isInterrupted():是否被终止
 *                     终止线程,在Java中都只是提醒建议,真正要不要终止需要线程本身来决定是否要终止。
 */
public class thread_method {
    private static boolean isRunning = true;
    /**
     * // 在声明isRunning这个变量是犯了一个错误,我将这个变量声明到了main方法中。
     *
     *  main方法是一个静态方法,其作用范围仅限于方法内部,变量的作用范围仅限于局部变量,因此变量不能有访问控制修饰符。
     *
     *  private:主要用于修饰类成员(字段/方法),因而private修饰符适用于类级别的字段和方法,而不适用于方法内部的局部变量。
     *  static:
     *        类级别变量:变量用static修饰,并且声明在类体内但方法外部,则变量属于类级别变量。所有实例共享同一个变量。
     *        局部变量:变量没有static修饰,则为局部变量,仅在方法的作用范围内有效。
     */
    public static void main(String[] args) {

        // boolean isRunning = true;
        /**
         * // boolean isRunning = true;
         *  isRunning: 声明为局部变量,在此代码中是编译不了的。(这错误卡在了javac编译阶段,和jvm运行时没有关系)
         *
         *             变量捕获:作为lambda或者匿名内部类,都能捕获到外面一层作用域中的变量名,就可以使用的。
         *             变量捕获:有一个前置条件,就是变量得是final或者“事实”final,这样才能被捕获的,否则就不能被捕获。
         *
         *  isRunning此处不能报错,不能捕获的原因是:isRunning在下面被更改为了false,并不能“事实”final,所以不能被捕获。
         *                             解决方法:将下面isRunning的修改删除,此段代码就不会报错了。但是就达不到控制终止程序的效果。
         */

        // 自己写一个控制终止线程

        Thread thread = new Thread(() -> {
            // 终止线程结束的方式有:控制循环条件、是否return...
            while(isRunning) {
                /**
                 * 此处的isRunning是 内部类 访问 外部类的成员变量。
                 */
                System.out.println("线程任务");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            System.out.println("线程已终止");
        });
        thread.start(); // 创建线程并执行线程

        try {
            Thread.sleep(5000); // 5秒后结束线程,那么就需要改变控制条件
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("终止线程");
        isRunning = false;
    }
}

private、static修饰作为修饰符(上段代码中的问题一

private:
        主要用于修饰类成员(字段/方法),因而private修饰符适用于类级别的字段和方法,而不适用于方法内部的局部变量。
static:
       类级别变量:变量用static修饰,并且声明在类体内但方法外部,则变量属于类级别变量。所有实例共享同一个变量。
       局部变量:变量没有static修饰,则为局部变量,仅在方法的作用范围内有效。
main方法是一个静态方法,其作用范围仅限于方法内部,变量的作用范围仅限于局部变量,因此变量不能有访问控制修饰符。

变量捕获(上段代码中的问题二

 isRunning: 声明为局部变量,在此代码中是编译不了的。(这错误卡在了javac编译阶段,和jvm运行时没有关系)
变量捕获:作为lambda或者匿名内部类,都能捕获到外面一层作用域中的变量名,就可以使用的。
变量捕获:有一个前置条件,就是变量得是final或者“事实”final,这样才能被捕获的,否则就不能被捕获。
isRunning此处不能报错,不能捕获的原因是:isRunning在下面被更改为了false,并不能“事实”final,所以不能被捕获。
解决方法:将下面isRunning的修改删除,此段代码就不会报错了。但是就达不到控制终止程序的效果。

interrupt、isInterrupted方法终止线程代码

1、interrupt():不是唤醒方法,只是提醒线程终止。
               能够设置 线程内置的标志位boolean变量的值;
               除了能设置boolean值,还可以唤醒sleep等阻塞的方法;
2、isInterrupted(boolean): 线程内置的标志位boolean,true表示线程终止;false表示线程继续执行。
3、currentThread(): Thread类中的一个static方法,此方法是获取当前线程,能够获取到当前thread这个引用。

    在下面catch代码中有重要内容!!!

/**
 *  Thread提供的interrupt()方法和isInterrupted()方法实现控制终止程序
 *  1、interrupt():不是唤醒方法,只是提醒线程终止。
 *                 能够设置 线程内置的标志位boolean变量的值;
 *                 除了能设置boolean值,还可以唤醒sleep等阻塞的方法;
 *
 */
public class thread_isInterrupted_method {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                /**
                 *  currentThread(): Thread类中的一个static方法,此方法是获取当前线程,能够获取到当前thread这个引用。
                 *  isInterrupted(boolean): 线程内置的标志位boolean,true表示线程终止;false表示线程继续执行。
                 */
                System.out.println("线程任务");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // throw new RuntimeException(e);
                    e.printStackTrace();
                    /**
                     * // 打印异常信息后还能继续线程,线程并没有终止
                     *
                     *    导致这个现象的原因是:
                     *    上述代码中有sleep()方法,线程正在sleep时,
                     *    触发了interrupt()方法,就导致sleep()方法被唤醒,
                     *    唤醒的同时就会清除刚才改变的标志位(就又回到了false);
                     */

                    /**
                     *  是否要结束当前线程,看程序员如何写:
                     *  1、不想结束当前线程:那么就不写退出循环的代码;
                     *  2、想结束当前线程:break; // 就会直接结束当前线程
                     */

                }
            }
            System.out.println("线程已结束");
        });
        thread.start();

        try {
            Thread.sleep(3000);
            // 3秒后结束线程
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 改变线程内置的标志位boolean值
        thread.interrupt();
        // 使用interrupt()后,要不要结束线程都是线程自身决定的
    }
}

3、join():线程等待

重温isInterrupted方法和Interrupt方法

改变isInterrupted中的标志位,唤醒sleep方法,标志位又复原,所以终止代码需要自己写。

public static void main(String[] args) {
        Thread thread = new Thread(()->{
            //lambda创建线程
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("lambda thread!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();

                    //Thread.currentThread().interrupt(); // 因为标志位被改变,所以需要再改一次
                    if(Thread.currentThread().isInterrupted()) {
                        System.out.println("lambda thread is interrupt!");
                        break;
                    }
                }
            }
            System.out.println("lambda thread end!");
        });

        thread.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("main thread!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        thread.interrupt(); // 改变标志位,并唤醒了sleep,又将标志位重置

        System.out.println("main end!");
    }

 join()方法,谁阻塞

在哪个方法中调用的xxx.join(),哪个方法就阻塞,xxx就执行。

package thread_wait;
/**
 *   main中调用join的两种情况:
 *   1、lambda thread线程已经结束,此时join会立即返回(没涉及到任何阻塞,继续向下执行代码);
 *   2、lambda thread线程还没结束,此时join会阻塞等待,一直等待到lambda thread线程结束之后,join才会解除阻塞,继续执行;
 *   * 在哪个线程里面调用join,这个线程就后结束!
 *
 *   阻塞:该线程暂时不参与CPU调度执行;
 *
 *   谁调用join谁就阻塞:
 *   // 在代码中有线程main、t1、t2
 *   // eg:在main线程中调用t1.join(),main线程则会阻塞,t1、t2都正常运行;
 *   // eg:在t1线程里调用t2.join(),t1线程会阻塞,t2、main线程正常执行;
 *   // * main线程不能被join();
 *
 *
 *
 */

public class test_3 {
    // main线程和thread线程之间的顺序是不确定的
    // 如果希望代码里的thread先结束,main线程后结束,可以在main线程中使用线程等待join();因为系统原生api叫pthread_join(linux)
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 4; i++) {
                System.out.println("lambda thread!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("lambda thread end!");
        });

        thread.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("main thread!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        try {
            thread.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 这段代码的意思:让main线程等待,lambda thread线程先结束。
        // 当加上这个等待代码时就开始报错了:
        // InterruptedException被捕获并打印了堆栈跟踪,但应该进一步的处理而不仅仅只是打印。
        /**
         *  join():当时没有抛出异常,所以报错了。
         */

        System.out.println("main end!");
    }
}

多个线程同时join(),执行顺序

线程是并发执行的,线程是各自调度各自的

package thread_wait;

public class test_4 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                System.out.println("thread1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("thread1 end!");
        });

        Thread thread2 = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("thread2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("thread2 end!");
        });

        thread1.start();
        thread2.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("main thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        try {
            thread1.join();
            thread2.join();
            // 线程是并发执行的,线程是各自调度各自的;
            /**
             *  这里可以体现,并不是谁join,谁就先结束。
             *  thread1.join():main线程调用thread1.join,就是让main线程阻塞等待thread1,和thread2没有任何关系;
             *  thread2.join():main线程调用thread2.join(),又让main等待thread2;
             */

            // thread1、thread2谁在上谁在下,效果一样,总的等待时间都是thread1、thread2运行比较长的时间;
            /**
             *  在main线程中调用多个join
             *  先执行thread2.join(),如果thread2还没结束,thread2.join()就阻塞等待;
             *  thread2结束之后,main继续执行thread1.join(),再等待thread1结束;
             */
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println("main end!");
    }
}

join()、join(long millis)、join(long millis, int nanos)

package thread_wait;

/**
 *  t.join():无参数的,就是死等待,只要t不结束,join就会一直等待;
 *  join(long millis):等待多少毫秒
 *  join(long millis, int nanos):等待多少毫秒,多少纳秒
 */
public class test_5 {
    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("thread1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("thread1 end!");
        });


        Thread thread2 = new Thread(()->{
            try {
                Thread.sleep(1000);
                thread1.join();
                // 让thread2线程等待,thread1、main继续执行;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            for (int i = 0; i < 5; i++) {
                System.out.println("thread2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("thread2 end!");
        });

        for (int i = 0; i < 5; i++) {
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        thread1.start();

        try {
            thread2.join();
            // 让main线程等待thread2线程,但是thread1、thread2继续执行;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        thread2.start();

        System.out.println("main end!");
    }
}

 4、sleep():休眠

sleep:是控制线程休眠的时间,而不是两个代码之间的执行时间

/**
 *  currentTimeMillis():获取当前时间(毫秒级时间戳)
 *
 *  sleep:是控制线程休眠的时间,而不是两个代码之间的执行时间;
 *
 *  方法上带有native的方法叫做“本地方法”,方法就是在jvm内部通过cpp代码实现的;
 *
 */
public class test_6 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("beg:"+System.currentTimeMillis());
        Thread.sleep(2000); // 前后时间间隔是大于休眠时间
        // 休眠状态,线程一定不会去CPU上执行的(阻塞),当休眠时间到之后,线程从阻塞状态恢复到就绪状态,不代表线程就能立即去CPU上执行。
        System.out.println("end:"+System.currentTimeMillis());
    }
}

5、线程状态

  线程的状态:(pcb的状态)

1、NEW :Thread对象有了,但是还没开始调用start,系统内部的线程还未创建。 

2、TERMINATED :线程已经中终止了,内核中的线程已经销毁了,但是Thread对象还在。

3、RUNNABLE :就绪状态,指的是这个线程“随叫随到”

         a:这个线程正在CPU上执行;

         b:这个线程虽然没在CPU上执行,随时可以调度到CPU上执行; 

4、阻塞:下面都为阻塞状态,只是进入阻塞的原因不同 

        a :WAITING -》死等,进入的阻塞状态(join-死等) 

        b :TIMED_WAITING -》带有超时间的等,进入阻塞状态(join(时间)/sleep(时间)-带时间的等) 

        c :BLOCKED -》进行锁竞争,进入阻塞状态 

package thread_state;

/**
 *  线程的状态:(pcb的状态)
 *  1、NEW :Thread对象有了,但是还没开始调用start,系统内部的线程还未创建。
 *  2、TERMINATED :线程已经中终止了,内核中的线程已经销毁了,但是Thread对象还在。
 *  3、RUNNABLE :就绪状态,指的是这个线程“随叫随到”
 *               a:这个线程正在CPU上执行;
 *               b:这个线程虽然没在CPU上执行,随时可以调度到CPU上执行;
 *  4、阻塞:下面都为阻塞状态,只是进入阻塞的原因不同
 *         a :WAITING -》死等,进入的阻塞状态(join-死等)
 *         b :TIMED_WAITING -》带有超时间的等,进入阻塞状态(join(时间)/sleep(时间)-带时间的等)
 *         c :BLOCKED -》进行锁竞争,进入阻塞状态
 *
 */

public class test_1 {

    // TERMINATED
    public static void main2(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            System.out.println("TERMINATED");
        });
        thread.start();
        thread.join(); // 这段代码的目的:确保thread线程已经执行完毕了。

        System.out.println("当前状态:" + thread.getState());
    }
    public static void main1(String[] args) {
        // NEW
        Thread thread = new Thread(()->{
            System.out.println("NEW");
        });
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值