小解——Java线程池的使用

前言:本文将讲解Java线程池的一些用法,涉及到的接口,类(Executor,Executors,ExecutorService),如何通过线程池管理线程,使我们的程序更加高效。

首先,写一个实现Runnable的类

 

public class ListOff implements Runnable{

    protected int countDown = 5;
    private static int taskCount = 0;
    private final int id = taskCount++;
    
    public ListOff(){}
    public ListOff(int countDown){
        this.countDown = countDown;
    }
    
    public String status() {
        return "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!") + ").";
    }
    
    @Override
    public void run() {
        while (countDown-- > 0) {
            System.out.println(status());
            Thread.yield();
        }
    }
}


 

代码很简单,主要是让该线程每次打印一下当前countDown的值,为稍后执行多个线程的时候作对比,显示线程之间是如何工作的。


这是一个线程,假如我们不使用线程池管理,那么,当我们有多个线程的时候,是这样的:


—————忧郁又带着些调皮的分割线(使用多线程)——————

 

public class BasicThreads {

    public static void main(String[] args) {
        
        Thread t = new Thread(new ListOff());
        Thread t1 = new Thread(new ListOff());
        Thread t2 = new Thread(new ListOff());
        t.start();
        t1.start();
        t2.start();
        System.out.println("Waiting for ListOff!");
    }
}


执行结果:

 

Waiting for ListOff!
#0(4).
#2(4).
#1(4).
#2(3).
#1(3).
#2(2).
#1(2).
#2(1).
#1(1).
#2(Liftoff!).
#1(Liftoff!).
#0(3).
#0(2).
#0(1).
#0(Liftoff!).


 

分析:没啥好分析,错综繁乱的结果,这里解释一下为什么“Waiting for ListOff!”会在最前方,因为Main方法本身就是一个线程。所有他和其他线程并排执行,可先可后。而且,他们的执行顺序不是我们认为可以控制的,而是由Java线程调度机制分配的。而且这个分配会产生一定的内存开销,不过在JDK1.5之后,已经将这个开销降至很小,跟线程给我们带来的好处比起来,几乎可以忽略不计。

显然,如果通过这种方法使用线程,一个线程执行完之后,垃圾回收器会在某个时刻将这个对象回收,然后每次需要的时候,又要重新创建线程。显然,假如我们整个项目贯穿了线程,那么这将是一个可以进行效率优化的好地方。

JDK 1.5的java.util.concurrent包中的执行器(Executor)将可以帮我们管理Thread对象,那就是线程池,从而简化并发编程。

有多种方式设置我们的线程池,先不多说,且看他如何帮我们管理Thread对象。

 
———————忧郁又带着些调皮的分割线(可变大小线程池小例子)——————

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPool {

    public static void main(String[] args) {
        
        //可变大小线程池
          ExecutorService exec = Executors.newCachedThreadPool();
          for (int i= 0; i<3; i++) {
              exec.execute(new ListOff());
          }
          exec.shutdown();
    }
}


执行结果:

 

#0(4).
#1(4).
#2(4).
#1(3).
#2(3).
#1(2).
#0(3).
#2(2).
#2(1).
#0(2).
#2(Liftoff!).
#0(1).
#1(1).
#0(Liftoff!).
#1(Liftoff!).


 

分析:其实执行结果和上一个的原理是一样的,但是呈现出来的结果不一样,因为线程的调度不是我们可以预测的。但为什么说使用了这个会闭上一个好呢?

 
假如线程贯穿了整个项目,那么,使用以上的方法,垃圾回收器自动回收线程,而是由ExecutorService管理,当一个线程执行完毕,将线程对象放到线程池,当我们需要线程的时候,他又从线程池中取出来,这样一来,假如线程用的多的话,我们就可以在创建线程,回收线程中节省大量的时间,从而提高效率。


但是,可能有人会问,怎么控制线程池中线程的数量呢?Good Question!每个项目的需求不一样,所需的线程数量也不一样,当我们需要设定线程熟的时候,且看我们的下一个例子:


————忧郁又带着些调皮的分割线(固定大小线程池小例子)————————

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPool {

    public static void main(String[] args) {
        
        //固定大小线程池
        ExecutorService exec = Executors.newFixedThreadPool(2);
        for (int i= 0; i<3; i++) {
            exec.execute(new ListOff());
        }
        exec.shutdown();
    }
}


执行结果:

 

#1(4).
#0(4).
#0(3).
#0(2).
#0(1).
#0(Liftoff!).
#2(4).
#2(3).
#2(2).
#2(1).
#2(Liftoff!).
#1(3).
#1(2).
#1(1).
#1(Liftoff!).


 

分析:这个结果可就有意思了!我故意把线程数设置为2,而我们有三个线程,为了让我们更加了解线程池的原理,我们就来分析一下结果。


由于我们的线程池只能放两个线程,所以我们猜测,一次最多只能有两个线程同时执行,假如两个有一个执行完毕,才会进行第三个线程。执行结果和我们猜测的一样,先执行第0个,第1个线程,看,由于线程具有不可预测性,所以线程0和1执行的时候,是没有先后顺序的,比如我的执行结果就是先打印线程1.

当线程池把线程0执行完毕以后,我们的线程2才闪亮登场,并且,线程2比线程1还先结束。

 
最后我还要提一句,Sun还为们提供了单一线程池,为什么呢?假如我们具有不可线程共享的资源,我们就可以使用单一线程池,这样就可以不必使用锁了。不过具体的应用,由于本人才疏学浅,没有这方面的项目经验,目前还不得知,为了让读者最大化、系统化的了解线程池,我还是决定把它写下来,希望有一定耐心的人能看到(我假设很多人看不到这里,因为确实很长,很枯燥,加上我讲的不好),

实践是检验理论的唯一标准,上代码:

 

———————忧郁又带着些调皮的分割线(单一线程池小例子)——————

 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadPool {

    public static void main(String[] args) {
       
        //单一线程池
        ExecutorService exec = Executors.newSingleThreadExecutor();
        for (int i= 0; i<3; i++) {
            exec.execute(new ListOff());
        }
        exec.shutdown();
    }
}


执行结果:

 

#0(4).
#0(3).
#0(2).
#0(1).
#0(Liftoff!).
#1(4).
#1(3).
#1(2).
#1(1).
#1(Liftoff!).
#2(4).
#2(3).
#2(2).
#2(1).
#2(Liftoff!).


 

分析:假如你已经猜到了结果,那么恭喜您,你已经基本了解线程池了。如果你没有猜到结果,那么,你可以去面壁。


小结:有点长,但其实不难,其实只知道了线程池,只是起步,假如想在实际项目中应用,那还是需要在实践中学习的,比如,你的线程池中的一个线程执行出现异常时,你该如何处理,假如你想要知道每个线程的执行结果,你该如何去做?希望你们能从本篇文章学会相关知识。


最后:由于本人才疏学浅,也是一枚还在实习的菜鸟,所讲解的东西肯定会有不足甚至有着严重的技术错误,欢迎大家批评指正,在交流中成长。如果有读者有不明白的地方,随时欢迎留言提问,咱们相互探讨一下,谢谢!

 

 

数据结构是计算机科学中研究数据组织、存储和管理的一门学科。一元多项式是数学中的概念,它由一个变量和对应的系数构成。一元多项式运算器是一个能够对一元多项式进行各种运算的程序或工具。 在Java中实现一元多项式运算器,可以使用链表或数组等数据结构来表示和存储多项式。以下是一个简单的示例代码: ```java import java.util.*; class Term { int coefficient; int exponent; public Term(int coefficient, int exponent) { this.coefficient = coefficient; this.exponent = exponent; } } class Polynomial { List<Term> terms; public Polynomial() { terms = new ArrayList<>(); } public void addTerm(int coefficient, int exponent) { terms.add(new Term(coefficient, exponent)); } public Polynomial add(Polynomial other) { Polynomial result = new Polynomial(); result.terms.addAll(this.terms); for (Term term : other.terms) { boolean found = false; for (Term existingTerm : result.terms) { if (existingTerm.exponent == term.exponent) { existingTerm.coefficient += term.coefficient; found = true; break; } } if (!found) { result.terms.add(term); } } return result; } public Polynomial multiply(Polynomial other) { Polynomial result = new Polynomial(); for (Term term1 : this.terms) { for (Term term2 : other.terms) { int coefficient = term1.coefficient * term2.coefficient; int exponent = term1.exponent + term2.exponent; result.addTerm(coefficient, exponent); } } return result; } public void print() { for (Term term : terms) { System.out.print(term.coefficient + "x^" + term.exponent + " + "); } System.out.println(); } } public class PolynomialCalculator { public static void main(String[] args) { Polynomial p1 = new Polynomial(); p1.addTerm(2, 3); p1.addTerm(4, 2); p1.addTerm(1, 0); Polynomial p2 = new Polynomial(); p2.addTerm(3, 2); p2.addTerm(1, 1); p2.addTerm(5, 0); Polynomial sum = p1.add(p2); Polynomial product = p1.multiply(p2); System.out.println("Sum:"); sum.print(); System.out.println("Product:"); product.print(); } } ``` 这个示例代码实现了一个简单的一元多项式运算器,可以进行多项式的加法和乘法运算。你可以根据需要扩展该代码,添加其他运算功能。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值