zoukankan      html  css  js  c++  java
  • Java多线程的创建

    做实验的过程中需要用到多线程,许久不用有点儿生疏了,现在查资料做个多线程创建的方法记录。

    Java使用线程大致有以下四种方法:

    • 继承Thread类,重写run方法。(Thread类本身也实现了Runnable接口)
    • 实现Runnable接口,重写run方法。
    • 实现Callable接口,重写call方法(有返回值)
    • 使用线程池(有返回值)

    1.继承Thread类,重写run方法

    每次创建一个新的线程,都需要新建一个Thread子类的对象。
    一个线程调用两次start()方法将会抛出线程状态异常。
    继承Thread类的方式是多个线程各自完成各自的任务。
    创建线程实际调用的是父类Thread空参的构造器。

    public class Test {
    	public static void main(String[] args) {
    		for (int i = 0; i < 10; i++) {
    			MyThread thread = new MyThread();
    			thread.satrt();
    		}
    		System.out.println("This is main thread");
    	}
    }
    
    public class MyThread extends Thread {
    	@Override
    	public void run() {
    		System.out.println("This is MyThread.");
    	}
    }
    

    2.实现Runnable接口,重写run()方法

    覆写Runnable接口实现多线程,可以避免单继承局限。不论创建多少个线程,只需要创建一个Runnable接口实现类的对象。
    创建线程实际调用的Thread类Runnable类型参数的构造器。
    实现Runnable接口的方法是多个线程共同完成一个任务。

    public class Test {
    	public static void main(String[] args) {
    		Task task = new Task();
    		for (int i = 0; i < 10; i++) {
    			Thread thread = new Thread(task);
    			thread.satrt();
    		}
    		System.out.println("This is main thread");
    	}
    }
    
    public class Task implements Runnable {
    	@Override
    	public void run() {
    		System.out.println("This is MyThread.");
    	}
    }
    

    3.实现Callable接口,重写call()方法

    自定义类实现Callable接口时,必须指定泛型,该泛型即返回值的类型。
    每次创建一个新的线程,都需要创建一个新的Callable接口的实现类。
    启动线程的过程:

    • 创建一个Callable接口的实现类的对象实例。
    • 创建一个FutureTask对象,传入Callable类型的参数。
    • 调用Thread类重载参数为Runnable的构造器创建Thread对象,将FutureTask作为参数传入。
      线程允许完后获取返回值:
    • 使用FutureTask的get()方法。
    public class Test {
    	public static void main(String[] args) {
    		for (int i = 0; i < 10; i++) {
    			Task task = new Task();
    			FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
                Thread thread = new Thread(futureTask);
                thread.start();
                try {
                    System.out.println("The result is : " + futureTask.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
    		}
    		System.out.println("This is main thread");
    	}
    }
    
    public class Task implements Callable<Integer> {
    	@Override
    	public Integer call() {
    		int result = 0;
    		for (int i = 0; i < 10000; i++)
    			result += i;
    		return result;
    	}
    }
    

    FutureTask的get()方法在调用的时候会阻塞,直到当前的线程完成运行后将结果返回。

    4.使用线程池

    在java.util.concurrent包下,提供了一系列与线程池有关的类。合理使用线程池,可以带来诸多好处:

    • 降低资源消耗,通过重复利用已创建的线程来降低线程创建和销毁造成的消耗。
    • 提高响应速度,当任务到达时,任务可以不必等到新线程创建就能立即运行。
    • 提高线程的可管理性,线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。
      线程池可以应对突然大爆发的访问,通过有限个固定线程为大量的操作服务,减少创建和销毁线程所需的时间。
      使用线程池的过程:
    • 创建线程池。
    • 创建任务。
    • 执行任务。
    • 关闭线程池。

    这里使用一个固定大小的线程池来举例子。

    public class Test {
    
    	private static final int THREAD_POOL_SIZE = 5;
    
    	public static void main(String[] args) {
    		ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
    		Task task = new Task();
    		FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
    		executorService.submit(futureTask);
    		executorService.shutdown();
    		try {
    			System.out.println("The result is : " + futureTask.get());
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		} catch (ExecutionException e) {
    			e.printStackTrace();
    		}
    		System.out.println("This is main thread");
    	}
    }
    
    public class Task implements Callable<Integer> {
    	@Override
    	public Integer call() {
    		int result = 0;
    		for (int i = 0; i < 10000; i++)
    			result += i;
    		return result;
    	}
    }
    

    5.对比

    可以将java中的线程创建方式分为两大类:一类是继承Thread类实现多线程;另一类是通过实现Runnable或者Callable接口实现多线程。
    下面来分析一下这两类实现多线程方式的优劣:

    通过继承Thread实现多线程

    • 优点
      1.实现简单,而且要获取当前线程,无需调用Thread.currentThread()方法,直接使用this即可获取当前线程。
    • 缺点
      1.线程已经继承了Thread类了,就不能继承其他类。
      2.多个线程不能共享同一份资源。

    通过实现Runnable或Callable接口实现多线程

    • 优点
      1.线程类只是实现了接口,还可以继承其他类。
      2.多个线程可以使用同一个target对象,适合多个线程处理同一个任务的情况。
    • 缺点
      1.较第一类方法,编程较为复杂。
      2.要访问当前线程,必须使用Thread.currentThread()方法。

    综上 :使用第二类方法较多!

  • 相关阅读:
    《演讲之禅》助你成长为一名合格程序员
    JavaScript中设置元素class的三种方法小结
    数据类型和Json格式
    JavaScript给onclick事件赋值,动态传参数实例辩错
    JSON.parse()和JSON.stringify()使用
    javascript写在<head>和<body>里的区别
    Source Insight 相关
    串口接收字符时,最后一个字符延时发送
    嵌入式编程中调试问题全记录
    新版数采仪开发问题全记录
  • 原文地址:https://www.cnblogs.com/xiepl1997/p/13884967.html
Copyright © 2011-2022 走看看