JAVA-16.1-线程常用方法、线程生命周期、线程组、线程池、计时器

来源:互联网 发布:如何自学软件编程 编辑:程序博客网 时间:2024/05/20 03:44

一:线程中的一些方法(线程中存在的现象)
  1.1 线程加入
    public final void join()
    等待该线程运行完毕,然后剩下的线程再一起抢占CPU执行权

package com.edu.exercise_01;public class MyThread extends Thread{    @Override    public void run() {        for (int i = 0; i < 5; i++) {            System.out.println(getName()+" "+i);        }    }}
package com.edu.exercise_01;/** * 1.1 线程加入        public final void join()        等待该线程中止,其他线程才能继续抢着执行 */public class Test {    public static void main(String[] args) throws Exception {        MyThread mt1 = new MyThread();        MyThread mt2 = new MyThread();        MyThread mt3 = new MyThread();        mt1.setName("张三");        mt2.setName("李四");        mt3.setName("王五");        mt1.start();        mt1.join();        mt2.start();        mt3.start();    }}//运行结果://张三 0//张三 1//张三 2//张三 3//张三 4//李四 0//李四 1//李四 2//王五 0//李四 3//王五 1//李四 4//王五 2//王五 3//王五 4

  1.2 线程礼让
    public static void yield():暂停当前正在执行的线程对象,并执行其他线程。
    作用:让线程间的执行更和谐一些,但是实际上做不到。可以通过后面讲解的知识来实现。

package com.edu.exercise_02;public class MyThread extends Thread{    @Override    public void run() {        for (int i = 0; i < 10; i++) {            System.out.println(getName()+"  "+i);            //实现线程礼让            //public static void yield():暂停当前正在执行的线程对象,并执行其他线程。             //作用:让线程间的执行更和谐一些,但是实际上做不到            Thread.yield();        }    }}
package com.edu.exercise_02;public class Test {    public static void main(String[] args) {        MyThread mt1 = new MyThread();        MyThread mt2 = new MyThread();        MyThread mt3 = new MyThread();        mt1.setName("小张");        mt2.setName("小李");        mt3.setName("小王");        mt1.start();        mt2.start();        mt3.start();        }}

  1.3 线程死亡
    public final void stop():直接杀死被清理掉
    public void interrupt():直接杀死,被清理之前前,会将剩下的代码执行完毕。

package com.edu.exercise_03;import java.text.SimpleDateFormat;import java.util.Date;public class MyThread extends Thread{    @Override    public void run() {        //获取开始时间        System.out.println("StartTime:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));        //休眠10秒        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            System.out.println("被终止了");        }        //获取结束时间        System.out.println("EndTime:"+new SimpleDateFormat("HH:mm:ss").format(new Date()));    }}
package com.edu.exercise_03;/** * 1.3 线程死亡   public final void stop():直接杀死(被清理)   public void interrupt():直接杀死,在被清理之前会将剩下的代码执行完毕,然后才被清理 * */public class Test {    public static void main(String[] args) {        //创建线程对象        MyThread mt = new MyThread();        //开启线程对象        mt.start();        //主线程休眠3秒,睡眠的过程中将mt线程杀死        try {            Thread.sleep(3000);            mt.interrupt();//首先输出StartTime:08:54:40                            //3秒后输出:                            /**      被终止了                                     EndTime:08:54:43                            */        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }/*              //主线程休眠3秒,睡眠的过程中将mt线程杀死        try {            Thread.sleep(3000);            mt.stop();//首先输出StartTime:08:57:13                      //3秒后输出结果只有StartTime:08:48:50,并且终止线程                      //stop划了一条横线表示该方法已经过时,但是还可以使用        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }*/          }}

  1.4 线程休眠
    static void sleep(long millis) 线程睡眠
二:线程的生命周期(画图讲解),面试题
  1.新建
  2.就绪
  3.运行
  4.有可能阻塞
  5.死亡
这里写图片描述

三:线程组
  3.1线程组:Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
  注意:默认情况下,所有的线程都属于主线程组。
  3.2线程组使用的一般步骤:
  ① a. 如果是给线程分组、命名,则首先创建MyRunnable类实现Runnable接口,重写run()方法;
    b. 如果是仅仅获取线程名称等,可以创建MyThread类继承Thread类,重写run()方法。
  ②创建线程组,并给线程组取名字
    ThreadGroup tg = new ThreadGroup(“我的线程组”);
  ③给线程设置分组
    a. MyRunnable mr = new MyRunnable();
     Thread t1 = new Thread(tg, mr);
    或者:
    b. Thread t2 = new Thread(tg, new MyRunnable());
  ④获取线程组对象
    ThreadGroup tg1 = t1.getThreadGroup();
  ⑤获取线程组对象的名称
    String name = tg1.getName()
案例1:创建线程获取对应的线程组对象,并获取名称

package com.edu.exercise_04;public class MyExtends extends Thread{    @Override    public void run() {     }}
package com.edu.exercise_04;/** 案例1:创建线程获取对应的线程组对象,并获取名称 *  *    1.默认情况下,所有的线程都属于主线程组。      2. public final ThreadGroup getThreadGroup():获取线程对应的线程组对象      3. 线程组对象掉用getName(),获取线程组对象的名称,返回值是String * */public class TestExtends {    public static void main(String[] args) {        //创建2个线程        MyExtends mt1 = new MyExtends();        MyExtends mt2 = new MyExtends();        //获取线程的线程组对象        ThreadGroup tg1 = mt1.getThreadGroup();        ThreadGroup tg2 = mt2.getThreadGroup();        //获取线程组对象的名称        System.out.println(tg1.getName());//main        System.out.println(tg2.getName());//main    }}

案例2:创建线程组对象,给线程分配线程组

package com.edu.exercise_04;public class MyRunnable implements Runnable{    @Override    public void run() {     }}
package com.edu.exercise_04;/** 案例2:创建线程组对象,给线程分配线程组 *  * 构造一个新线程组 public ThreadGroup(String name) * 给线程设置分组 Thread(ThreadGroup group, Runnable target),注意需要的是实现Runnable接口的实现类对象 */public class TestRunnable {    public static void main(String[] args) {        //创建实现类对象        MyRunnable mr = new MyRunnable();        //构造一个新线程组 public ThreadGroup(String name)        ThreadGroup tg = new ThreadGroup("我的线程组");        //给线程设置分组 Thread(ThreadGroup group, Runnable target)        Thread t1 = new Thread(tg, mr);        Thread t2 = new Thread(tg, new MyRunnable());        //获取线程名称        System.out.println(t1.getThreadGroup().getName());//我的线程组        System.out.println(t2.getThreadGroup().getName());//我的线程组    }}

四:线程池
4.1为什么要使用线程池?
  程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。
  线程池的特点:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池
  线程池如何创建?JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法public static ExecutorService newFixedThreadPool(int nThreads)
  
4.2线程池的使用步骤:
  ①创建线程池对象
    ExecutorService pool = Executors.newFixedThreadPool(2);
  ②创建Runnable实例或者Callable实例
  (创建Runnable实例,重写run()方法,没有返回值;或者创建Callable<>实例重写call()方法,有返回值,返回值类型必须是引用类型)
    MyRunnable my = new MyRunnable();
  ③提交Runnable实例
    pool.submit(my);
  ④关闭线程池
    pool.shutdown();
案例1:实现Runnable接口实现线程池的使用

package com.edu.exercise_05;public class MyRunnable implements Runnable{    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName()+"---"+i);        }    }}
package com.edu.exercise_05;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class MrThreadPool {    public static void main(String[] args) {        //案例1:实现Runnable接口实现线程池的使用        //1.创建线程池对象        //ExecutorService pool = Executors.newFixedThreadPool(3);        ExecutorService mrpool = Executors.newFixedThreadPool(2);        //2.提交给线程池两个任务,都是打印0-99        //创建Runnable实例,        //MyRunnable my = new MyRunnable();        MyRunnable mr1 = new MyRunnable();        MyRunnable mr2 = new MyRunnable();        //3.提交任务        mrpool.submit(mr1);//一旦提交任务,就会自动开启线程,并执行run()方法中的代码,                           //每个线程任务执行完毕,线程会自动关闭,但是并没有被终止,                           //而是再次再次回到线程池中成为空闲状态,等待下一个对象来使用。        mrpool.submit(mr2);        //关闭线程池        //void shutdown()        mrpool.shutdown();    }}

案例2:实现Callable接口实现线程池的使用

package com.edu.exercise_05;//Callable接口和Runnable接口很相似,不同的是前者有返回值,后者没有返回值import java.util.concurrent.Callable;public class MyCallable implements Callable{    @Override    public Object call() throws Exception {        for (int i = 0; i < 100; i++) {            System.out.println(Thread.currentThread().getName()+"---"+i);        }        return null;    }}
package com.edu.exercise_05;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class McThreadPool {    public static void main(String[] args) {        //案例2:实现Callable接口实现线程池的使用        //1.创建线程池        ExecutorService mcpool = Executors.newFixedThreadPool(2);        //2.创建任务        MyCallable mc1 = new MyCallable();        MyCallable mc2 = new MyCallable();        //3.提交任务        mcpool.submit(mc1);        mcpool.submit(mc2);        //4.关闭线程池        mcpool.shutdown();    }}

案例3:实现Callable接口实现线程池的使用,实现多线程求和,1-10之和,1-100之和

package com.edu.exercise_06;//实现Callable接口实现线程池的使用,实现多线程求和,1-10之和,1-100之和import java.util.concurrent.Callable;/** * 要想在主函数中直接给MyCallable类初始化,把开始值和结束值传进来,就应该想到利用构造方法传参 * */public class MyCallable implements Callable<Integer>{    private int start;    private int end;    public MyCallable(int start , int end){        this.start = start;        this.end = end;    }    @Override    public Integer call() throws Exception {        //求和        int sum = 0;        for (int i = start; i < end + 1; i++) {            sum+=i;        }        return sum;    }}

测试类:

package com.edu.exercise_06;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class Test {    public static void main(String[] args) throws Exception {        //1.创建线程池对象        ExecutorService pool = Executors.newFixedThreadPool(2);        //2.创建任务        MyCallable mc1 = new MyCallable(1, 10);        MyCallable mc2 = new MyCallable(1, 100);        //3.添加任务        Future<Integer> res1 = pool.submit(mc1);        Future<Integer> res2 = pool.submit(mc2);            //V get()如有必要,等待计算完成,然后获取其结果。        System.out.println(res1.get());        System.out.println(res2.get());        //4.关闭线程池        pool.shutdown();    }}

五:定时器
①Timer类
  public Timer()构造
  public void schedule(TimerTask task, long delay)延迟多久执行任务
  public void schedule(TimerTask task,long delay,long period)延迟多久执行任务,并以后每隔多久执行一次
  public void schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务
  public boolean cancel()取消这个任务

②TimerTask抽象类,用于创建一个计时任务
  public abstract void run()放的是所要执行的任务代码
案例1:演示以上方法的使用

package com.edu.exercise_07;import java.util.Timer;import java.util.TimerTask;//需求:在5秒钟后,在控制台打印一句话,helloworldpublic class TimerTest {    public static void main(String[] args) {        Timer t = new Timer();        //public void schedule(TimerTask task, long delay)延迟多久执行任务        //TimerTask是抽象类        t.schedule(new MyTimerTask(t), 5000);        //t.cancel();//如果在这里关闭的话,我们还没等任务执行完毕呢,计时器已经被关闭了    }}class MyTimerTask extends TimerTask{    private Timer t;    public MyTimerTask(Timer t){        this.t = t;    }    @Override    public void run() {        System.out.println("helloworld");        t.cancel();//等待任务结束,将计时任务取消    }}

案例2:定时删除文件

package com.edu.exercise_08;import java.io.File;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class Test {    public static void main(String[] args) throws Exception {        /**         * 案例:定时删除文件(需要在指定时间删除D://a.txt文件)         * 所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务         * 时间点:16:30:00         * 任务:删除D://a.txt文件         */        //1.创建定时器        Timer t = new Timer();        //2.指定的时间解析为日起对象        String time = "2017-05-21 16:31:00";        Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time);        //3.所用方法:schedule(TimerTask task, Date time) 安排在指定的时间执行指定的任务        t.schedule(new MyTimerTask(t), date);    }}class MyTimerTask extends TimerTask{    //构造传参    private Timer t;    public MyTimerTask(Timer t) {        this.t = t;    }    @Override    public void run() {        //任务:删除D://a.txt文件        File file = new File("D://a.txt");        file.delete();        t.cancel();    }   }
原创粉丝点击