多线程-基础(2)

第三种方式:使用内部类的方式

这并不是一种新的实现线程的方式,只是另外的一种写法。比如有些情况我们的线程就想执行一次,以后就用不到了。那么像上面两种方式(继承Thread类和实现Runnable接口)都还要再定义一个类,显得比较麻烦,我们就可以通过匿名内部类的方式来实现。使用内部类实现依然有两种,分别是继承Thread类和实现Runnable接口。

/**
 * 匿名内部类的方式创建线程
*/

public class CreateThread_Anonymous {
    
    
	
	public static void main(String[] args) {
    
    
		
		// 基于子类的方式
        new Thread() {
    
    
            @Override
            public void run() {
    
    
                while (true) {
    
    
                    printThreadInfo();
                }
            }
        }.start();
        
     // 基于接口的实现
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                while (true) {
    
    
                    printThreadInfo();
                }
            }
        }).start();
	}
	 /**
     * 输出当前线程的信息
     */
    private static void printThreadInfo() {
    
    
        System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
        try {
    
    
            Thread.sleep(1000);
        } catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }
    }
}

运行结果:
在这里插入图片描述
第四种方式:定时器

在应用中经常需要定期执行一些操作,比如要在凌晨的时候汇总一些数据,比如要每隔10分钟抓取一次某个网站上的数据等等,总之计时器无处不在。

在Java中实现定时任务有很多种方式,JDK提供了Timer类来帮助开发者创建定时任务,另外也有很多的第三方框架提供了对定时任务的支持,比如Spring的schedule以及著名的quartz等等。

  1. 指定时间点执行
/**
 * 定时任务
*/
public class CreateThread2_Timer {
    
    

    private static final SimpleDateFormat format =
            new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

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

        // 创建定时器
        Timer timer = new Timer();

        // 提交计划任务
        timer.schedule(new TimerTask() {
    
    
            @Override
            public void run() {
    
    
                System.out.println("定时任务执行了...");
            }
        }, format.parse("2017-10-11 22:00:00"));  //指定执行的时间
    }
}

运行结果:

在这里插入图片描述
2.间隔时间重复执行

/**
 * 定时任务
 *
*/
public class CreateThread2_Timer {
    
    

    public static void main(String[] args){
    
    

        // 创建定时器
        Timer timer = new Timer();

        // 提交计划任务
        timer.schedule(new TimerTask() {
    
    
            @Override
            public void run() {
    
    
                System.out.println("定时任务执行了...");
            }
        },new Date(), 1000);  //指定间隔的时间
    }
}

运行结果:

在这里插入图片描述
第五种方式:Future模式(带返回值的线程实现方式)

我们发现上面提到的不管是继承Thread类还是实现Runnable接口,发现线程执行完毕之后并无法获得线程的返回值。

但是使用这种方式创建线程比上面两种方式要复杂一些,步骤如下。
 创建一个类实现Callable接口,实现call方法。这个接口类似于Runnable接口,但比Runnable接口更加强大,增加了异常和返回值。
 创建一个FutureTask,指定Callable对象,做为线程任务。
 创建线程,指定线程任务。
 启动线程

代码如下:

/**
 * 带返回值的方式
 */
public class CreateThreadDemo3_Callable {
    
    

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

        // 创建线程任务
        Callable<Integer> call = () -> {
    
    
            System.out.println("线程任务开始执行了....");
            Thread.sleep(2000);
            return 1;
        };

        // 将任务封装为FutureTask
        FutureTask<Integer> task = new FutureTask<>(call);

        // 开启线程,执行线程任务
        new Thread(task).start();

        // ====================
        // 这里是在线程启动之后,线程结果返回之前
        System.out.println("这里可以为所欲为....");
        // ====================

        // 为所欲为完毕之后,拿到线程的执行结果
        Integer result = task.get();
        System.out.println("主线程中拿到异步任务执行的结果为:" + result);
    }
}

运行结果:

在这里插入图片描述
Callable中可以通过范型参数来指定线程的返回值类型。通过FutureTask的get方法拿到线程的返回值。

第六种方式:基于线程池的方式

我们知道,线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。

/**
 * 线程池
*/
public class CreateThreadDemo4_ThreadPool {
    
    

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

        // 创建固定大小的线程池
        ExecutorService threadPool = Executors.newFixedThreadPool(10);

        while (true) {
    
    
            // 提交多个线程任务,并执行
            threadPool.execute(new Runnable() {
    
    
                @Override
                public void run() {
    
    
                    printThreadInfo();
                }
            });
        }
    }

    /**
     * 输出当前线程的信息
     */
    private static void printThreadInfo() {
    
    
        System.out.println("当前运行的线程名为: " + Thread.currentThread().getName());
        try {
    
    
            Thread.sleep(1000);
        } catch (Exception e) {
    
    
            throw new RuntimeException(e);
        }

    }
}

运行结果:

在这里插入图片描述
欢迎留言讨论。

猜你喜欢

转载自blog.csdn.net/weixin_42409759/article/details/107883539