Java线程学习笔记

    1、判断线程存活

   

        1. 当线程run()或者call()方法执行结束,线程进入终止状态

        2. 当线程内发生异常,并且异常没有被捕获,线程进入终止状态

        3. 线程调用stop()方法后,线程进入终止状态(不推荐使用)

       

        当主线程结束时,其他线程不受任何影响,并不会随之结束。一旦子线程启动起来后,它就拥有和主线程相同的地位,它不会受主线程的影响。

        为了测试某个线程是否已经死亡,可以调用线程对象的isAlive()方法,当线程处于就绪、运行、阻塞3种状态时,该方法将返回true;当线程处于新建、死亡2种状态时,该方法将返回false。

/**

 * isAlive()方法练习

   */

   public class IsAliveDemo1 {

   public static void main(String[] args) throws InterruptedException {

       Thread t = new Thread(()->{

           for (int i = 0; i < 50; i++) {

               System.out.println(i);

           }

       });

       System.out.println("线程的状态:"+t.getState());//NEW

       System.out.println("线程启动前:"+t.isAlive());//false

       System.out.println("----------------------");

       t.start();

       System.out.println("线程的状态:"+t.getState());//RUNNABLE

       System.out.println("线程启动后:"+t.isAlive());//true

       System.out.println("----------------------");

       TimeUnit.SECONDS.sleep(5);

       System.out.println("线程的状态:"+t.getState());//TERMINATED

       System.out.println("线程结束后:"+t.isAlive());//false

   }

   }

/**

 *isAlive()方法练习2

 */

public class IsAliveDemo2 {

    public static void main(String[] args) throws InterruptedException {

        Thread t = new Thread(()->{

            for (int i = 0; i < 40; i++) {

                System.out.println(i);

                if(i==15){

                    synchronized (IsAliveDemo2.class){

                        try {

                            IsAliveDemo2.class.wait();

                        } catch (InterruptedException e) {

                            throw new RuntimeException(e);

                        }

                    }

                }

            }

        });

        //启动前获取状态

        System.out.println("线程启动前:"+t.isAlive());

        t.start();

        System.out.println("线程启动后:"+t.isAlive());

        //主线程休眠2秒,给予t线程充足的执行时间

        TimeUnit.SECONDS.sleep(2);

        System.out.println("线程抛出异常后:"+t.isAlive());

    }

}

       

        注意:不要对处于死亡状态的线程调用start()方法,程序只能对新建状态的线程调用start()方法,对新建状态的线程两次调用start()方法也是错误的。这都会引发IllegalThreadState Exception异常。

/**

 * 练习3

   */

   public class IsAliveDemo3 {

   public static void main(String[] args) throws InterruptedException {

       Thread t = new Thread(()->{

           for (int i = 0; i < 10; i++) {

               System.out.println(i);

           }

       });

       t.start();

       //t.start(); 抛出IllegalThreadStateException异常

       TimeUnit.SECONDS.sleep(2);

       System.out.println(t.getState());//TERMINATED

       //t.start(); 抛出IllegalThreadStateException异常

   }

   }

   2、线程控制

   (1)Join()

    join()方法相当于插入,例如在T2线程中调用了线程T1.join()方法,则T2线程会一直等待T1线程执行结束后再继续执行。

    就是在A线程中调用线程B的join()方法,线程A会一直等待直到线程B执行结束再执行,也可以理解为插队。

   

    注意:当T2线程执行过程中被T1线程Join,线程T1执行时,T2处于WAITING

/**

 * Join()方法

   */

   public class JoinDemo1 {

   public static void main(String[] args) throws InterruptedException {

       Thread t1 = new Thread(()->{

           for (int i = 0; i < 30; i++) {

               System.out.println(Thread.currentThread().getName()+"--------->"+i);

           }

       },"t1");

       Thread t2 = new Thread(()->{

           for (int i = 0; i < 30; i++) {

               System.out.println(Thread.currentThread().getName()+"#########"+i);

               if (i == 10){

                   try {

                       //t1线程调用t2线程的join()方法,插队执行

                       t1.join();

                   } catch (InterruptedException e) {

                       throw new RuntimeException(e);

                   }

               }

           }

       },"t2");

       t1.start();

       System.out.println(t1.getState());

       t2.start();

       //main t1 t2 三个线程交替执行

       for (int i = 0; i < 60; i++) {

           System.out.println(Thread.currentThread().getName()+"***********"+i);

       }

   }

   }


 

   (2)Join(long millis)

    如果T2线程执行过程中调用为了T1线程的join(long millis)方法,T2线程最多等待T1线程millis毫秒,到达时间后,如果T1线程没有结束,则和T2线程交替执行。

   

    注意:T2线程被T1线程join(millis)后,T2线程在等待T1线程执行的过程中处于TIMED_WAITING状态    

/**

 * Join()方法

   */

   public class JoinDemo2 {

   public static void main(String[] args) throws InterruptedException {

       Thread t1 = new Thread(()->{

           for (int i = 0; i < 50; i++) {

               System.out.println(Thread.currentThread().getName()+"-------->"+i);

               try {

                   TimeUnit.SECONDS.sleep(1);

               } catch (InterruptedException e) {

                   throw new RuntimeException(e);

               }

           }

       },"t1");

       Thread t2 = new Thread(()->{

           for (int i = 0; i < 200; i++) {

               System.out.println(Thread.currentThread().getName()+"##########"+i);

               if (i == 20){

                   //启动t1线程

                   t1.start();

                   try {

                       //在线程t2中插入

                       t1.join(3000);

                   } catch (InterruptedException e) {

                       throw new RuntimeException(e);

                   }

               }

           }

       },"t2");

       //启动进程

       t2.start();

       System.out.println("--------------------");

       //主线程休眠 让t2线程执行

       TimeUnit.SECONDS.sleep(2);

       //t2线程的状态

       System.out.println(t2.getState());//TIMED_WAITING

   }

   }

   (3)守护线程

    在后台运行的,并为其他的线程提供服务的线程被称为“后台线程”,又称为“守护线程”,JVM的垃圾回收线程就是典型的后台线程。

    特征:如果所有的前台线程都死亡,后台线程会自动死亡。

   

    守护线程必须在启动前将其守护状态设置为true,启动之后不能再将用户线程设置为守护线程,否则JVM会抛出一个InterruptedException异常。具体来说,如果线程为守护线程,就必须在线程实例的start()方法调用之前调用线程实例的setDaemon(true),设置其daemon实例属性值为true。

    守护线程存在被JVM强行终止的风险,所以在守护线程中尽量不去访问系统资源,如数据库连接。守护线程被强行终止时,可能会引发系统资源操作不负责任的中断,从而导致资源不可逆的损坏。

    守护线程创建的线程也是守护线程。在守护线程中创建的线程,新的线程都是守护线程。在创建之后,如果通过调用setDaemon(false)将新的线程显式地设置为用户线程,新的线程可以调整成用户线程。

/**

 * setDaemon()方法

   */

   public class DaemonDemo {

   public static void main(String[] args) {

       Thread t1 = new Thread(()->{

           for (int i = 0; i < 100; i++) {

               System.out.println(Thread.currentThread().getName()+"===="+i);

           }

       },"t1");

       //设置线程为守护线程 必须在启动前设置

       t1.setDaemon(true);

       t1.start();

       //主线程循环次数大幅少于守护线程,当前台线程执行结束时 守护线程不管是否执行完毕都会结束

       for (int i = 0; i < 10; i++) {

           System.out.println(Thread.currentThread().getName()+">>>>"+i);

       }

   }

   }


 

你可能感兴趣的:(java)