浅谈Thread和Runnable

来源:互联网 发布:剑三 点绛唇捏脸数据 编辑:程序博客网 时间:2024/06/13 10:40

浅谈Thread和Runnable

本文介绍Thread和Runnable创建线程的区别:

-两种创建线程方法的比较
-线程的生命周期
-线程的守护神-守护线程
- 总结
- 守护线程的代码


线程创建的两种方式比较:

  • 继承Thread类创建多线程:
   public class MyThread extends Thread{         @Override               public void run(){                   ...            }        }        MyThread  t = new MyThread();        t.start();
  • 实现Runnable接口:
 class MyThread implements Runnable{     @Override     public void run(){         ....     }   }MyThread mt = new MyThread ();Thread t = new Thread(mt);t.start();
  • 两种方式的比较:实现Runnable接口方式可以避免继承Thread方式由于Java单继承特性带来的缺陷。实现Runnable的代码可以被多个线程共享,适合于多个线程处理同一资源的情况.(具体见代码)

线程的生命周期:

  • 线程的生命周期中有几种状态,如下图:
    这里写图片描述
  • 创建状态:新建一个线程对象。如:Thread td = new Thread();
  • 就绪状态:创建了线程对象后,调用线程的start()方法(注意:此时线程只是进入了线程队列,等待获取CPU服务,具备了运行的条件,但并不一定已经开始运行了。)
  • 运行状态:处于就绪状态的线程,一旦获取了CPU资源,便进入到运行状态,开始执行run方法的逻辑。
  • 终止状态:线程的run方法执行完毕,或者线程调用了stop方法,线程进入终止状态。
  • 阻塞状态:一个正在执行的线程在某些情况下,由于某种原因而暂时让出了CPU资源,暂停了自己的执行,便进入了阻塞状态,如调用了sleep方法。

    线程的守护神

  • Java线程有两类:用户线程和守护线程。用户线程:运行在前台,执行具体的任务。守护线程:运行在后台,为前台线程服务。特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作。应用:数据库连接池中的监测线程、JVM虚拟机启动后的监测线程、垃圾回收线程。

  • 如何设置守护线程:可以通过Thread类的setDaemon(true)方法来设置当前线程为守护线程。注意事项:setDaemon(true)方法必须在start()方法前调用,否则会抛出IllegalThreadStateException异常。
  • 在守护线程中产生的线程也是守护线程。
  • 不是所有的操作都能分配给守护线程来执行,比如读写操作或者计算逻辑。理解:假如读写操作是守护线程,当读写操作执行到一半,所有的用户线程都结束了,守护线程会随着JVM一起结束工作。守护线程执行的读写操作还没完成,程序有异常。后面有程序讲解
  • 使用jstack生成线程快照:生成当前时刻线程的快照,即当前进程中所有线程的信息。帮助定位程序出现的原因。
  • jstack的使用:具体如下图
    这里写图片描述

  • 第二个参数pid对应的就是进程的进程id。使用如下图:
    这里写图片描述

    总结:

  • 首先,本文介绍了Thread和Runnable创建线程的区别。

  • 介绍了线程的生命周期和周期对应的代码和状态。
  • 再次介绍了守护线程的概念和jstack工具。

    守护线程的代码:

    /***创建一个守护线程,实现每一秒钟向文件写入一句话**/public class GuardThread implements Runnable{   @Override   public void run(){            System.out.println("守护线程:"+Thread.currentThread().getName()+"开始执行");    wirterFile();    System.out.println("守护线程:"+Thread.currentThread().getName()+"结束执行");   }  /** * 每一秒钟向文件中写入一句话 * @throws Exception */private void wirterFile(){               OutputStream fileOutPutStream = null;    try {        File daemonFile = new File("D:"+File.separator+"daemon.txt");        //第二个参数表示已追加的形式来写文件        fileOutPutStream = new FileOutputStream(daemonFile,true);        int count = 0;        while(count<1000){            fileOutPutStream.write(("word "+count+"\r\n").getBytes());            System.out.println("守护线程:"+Thread.currentThread().getName()+"写入 word "+count++);            /**             * 每写一次文件休眠一秒             */            Thread.sleep(1000);        }    }catch(Exception e){        e.printStackTrace();    }finally {        if(fileOutPutStream!=null){            try {                fileOutPutStream.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }    }}  
/**主线程类*/public class GuardThreadTest {     public static void main(String[] args) {        System.out.println("主线程"+Thread.currentThread().getName()+"开始执行");        GuardThread guardThread = new GuardThread();        Thread td = new Thread(guardThread);        //设置线程为守护线程        td.setDaemon(true);        //启动线程        td.start();        Scanner scanner = new Scanner(System.in);        //主线程阻塞 等待键盘输入        String keyWord = scanner.next();        System.out.println("主线程"+Thread.currentThread().getName()+"结束执行,键盘上输入的字:"+keyWord);    }}
1 0
原创粉丝点击