java编程中你偶遇过的池

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java编程中你偶遇过的池相关的知识,希望对你有一定的参考价值。

                                    你遇见过那么多池,却缺了phone池

1.String池

 

public static void main(String[] args) throws IOException {
        String s1 = "a"; 
        String s2 = "b"; 
        String s3 = "ab"; 
         
        String s4 = "ab"; 
        System.out.println("s3==s4 -> "+ (s3==s4)); 
 
        String s5 = "a"+"b"; 
        System.out.println("s3==s5 -> "+ (s3==s5)); 
         
        String s6 = s1+s2; 
        System.out.println("s3==s6 -> "+ (s3==s6)); 
         
        String s7 = new String("ab"); 
        System.out.println("s3==s7 -> "+ (s3==s7)); 
         
        final String s8 = "a" ;  
        final String s9 = "b" ; 
        String s10 = s8 + s9; 
        System.out.println("s3==s10 -> "+ (s3==s10));

 

    }

输出结果:

s3==s4 -> true

s3==s5 -> true

s3==s6 -> false

s3==s7 -> false

s3==s10 -> true

冯老师解释时间:

java中的字符串 :String类是不可变的(final),对String类的任何改变,都是返回一个新的String类对象。String 对象是 System.Char 对象的有序集合,用于表示字符串。String 对象的值是该有序集合的内容,并且该值是不可变的。

把String类的引用传递给一个方法,该方法对String的任何改变,对原引用指向的对象没有任何影响,这一点和基本数据类型相似。

 

String池 :String是不可改变的,为了提高效率Java引用了字符串池的概念,例如new String("abc");首先会在String池中创建一个对象“abc”,因为有NEW的存在所以会分配地址空间copy String池的内容。当出现的String对象在String池中不存在时即在String池中创建该对象。

 

s3、s4  ->  根据String的概念他们都指向了同一个缓冲池内的地址,所以结果为true。

 

s3、s5  ->  因为相加的两个为常量,所以编译器会把s5="a"+"b"优化为s5="ab",所以结果也为true。

 

s3、s6  ->  因为是两个变量的相加所以编译器无法优化,s1+s2即等同于(new StringBuilder(String.valueOf(s1))).append(s2).toString(); 在运行时,会有新的String地址空间的分配,而不是指向缓冲池中的“ab”。所以结果false。

 

s3、s7  ->  根据缓冲池的定义在new的时候实际会新分配地址空间,s7指向的是新分配的地址空间所以与缓冲池地址不同,所以为false。

 

s3、s10  ->  类似于s3与s5,因为是final类型编译器进行了优化所以相同。

 

 

 

 

 

 


二.线程池

1.什么是线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

2.线程池的功能

应用程序可以有多个线程,这些线程在休眠状态中需要耗费大量时间来等待事件发生。其他线程可能进入睡眠状态,并且仅定期被唤醒以轮循更改或更新状态信息,然后再次进入休眠状态。

3.四大线程池

(1) newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

 

Java代码
  1. package test;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.Executors;  
  4. public class ThreadPoolExecutorTest {  
  5.  public static void main(String[] args) {  
  6.   ExecutorService cachedThreadPool = Executors.newCachedThreadPool();  
  7.   for (int i = 0; i < 10; i++) {  
  8.    final int index = i;  
  9.    try {  
  10.     Thread.sleep(index * 1000);  
  11.    } catch (InterruptedException e) {  
  12.     e.printStackTrace();  
  13.    }  
  14.    cachedThreadPool.execute(new Runnable() {  
  15.     public void run() {  
  16.      System.out.println(index);  
  17.     }  
  18.    });  
  19.   }  
  20.  }  

 

线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
 
(2) newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

 

Java代码  
  1. package test;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.Executors;  
  4. public class ThreadPoolExecutorTest {  
  5.  public static void main(String[] args) {  
  6.   ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);  
  7.   for (int i = 0; i < 10; i++) {  
  8.    final int index = i;  
  9.    fixedThreadPool.execute(new Runnable() {  
  10.     public void run() {  
  11.      try {  
  12.       System.out.println(index);  
  13.       Thread.sleep(2000);  
  14.      } catch (InterruptedException e) {  
  15.       e.printStackTrace();  
  16.      }  
  17.     }  
  18.    });  
  19.   }  
  20.  }  
  21. }  
    因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
    定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

 

 

 

(3)  newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

 

Java代码  
  1. package test;  
  2. import java.util.concurrent.Executors;  
  3. import java.util.concurrent.ScheduledExecutorService;  
  4. import java.util.concurrent.TimeUnit;  
  5. public class ThreadPoolExecutorTest {  
  6.  public static void main(String[] args) {  
  7.   ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
  8.   scheduledThreadPool.schedule(new Runnable() {  
  9.    public void run() {  
  10.     System.out.println("delay 3 seconds");  
  11.    }  
  12.   }, 3, TimeUnit.SECONDS);  
  13.  }  
  14. }

 
表示延迟3秒执行。

 

定期执行示例代码如下:

 

Java代码  
  1. package test;  
  2. import java.util.concurrent.Executors;  
  3. import java.util.concurrent.ScheduledExecutorService;  
  4. import java.util.concurrent.TimeUnit;  
  5. public class ThreadPoolExecutorTest {  
  6.  public static void main(String[] args) {  
  7.   ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);  
  8.   scheduledThreadPool.scheduleAtFixedRate(new Runnable() {  
  9.    public void run() {  
  10.     System.out.println("delay 1 seconds, and excute every 3 seconds");  
  11.    }  
  12.   }, 1, 3, TimeUnit.SECONDS);  
  13.  }  
  14. }  

 



表示延迟1秒后每3秒执行一次。

 

 

 

(4) newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:

 

Java代码  
    1. package test;  
    2. import java.util.concurrent.ExecutorService;  
    3. import java.util.concurrent.Executors;  
    4. public class ThreadPoolExecutorTest {  
    5.  public static void main(String[] args) {  
    6.   ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();  
    7.   for (int i = 0; i < 10; i++) {  
    8.    final int index = i;  
    9.    singleThreadExecutor.execute(new Runnable() {  
    10.     public void run() {  
    11.      try {  
    12.       System.out.println(index);  
    13.       Thread.sleep(2000);  
    14.      } catch (InterruptedException e) {  
    15.       e.printStackTrace();  
    16.      }  
    17.     }  
    18.    });  
    19.   }  
    20.  }  
    21. }  

4.应用范围

 

1、需要大量的线程来完成任务,且完成任务的时间比较短。 WEB服务器完成网页请求这样的任务,使用线程池技术是非常合适的。因为单个任务小,而任务数量巨大

 

2、对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

 

3、接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现"OutOfMemory"的错误。

 

 

 

 

 


三.数据库连接池

1.为什么要用数据库连接池

最原始的数据库使用就是打开一个连接并进行使用,使用过后一定要关闭连接释放资源。由于频繁的打开和关闭连接对jvm包括数据库
都有一定的资源负荷,尤其应用压力较大时资源占用比较多容易产生性能问题。由此使用连接池的作用就显现出来

 

2.数据库连接池的原理
先打开一定数量的数据库连接,当使用的时候分配给调用者,调用完毕后返回给连接池,注意返回给连接池后这些连接并不会关闭,而是
准备给下一个调用者进行分配。由此可以看出连接池节省了大量的数据库连接打开和关闭的动作,对系统性能提升的益处不言而喻。

 

3.常用的数据库连接池


1. dbcp
dbcp可能是使用最多的开源连接池,原因大概是因为配置方便,而且很多开源和tomcat应用例子都是使用的这个连接池。
这个连接池可以设置最大和最小连接,连接等待时间等,基本功能都有。这个连接池的配置参见附件压缩包中的:dbcp.xml
使用评价:在具体项目应用中,发现此连接池的持续运行的稳定性还是可以,不过速度稍慢,在大并发量的压力下稳定性
有所下降,此外不提供连接池监控

2 c3p0
c3p0是另外一个开源的连接池,在业界也是比较有名的,这个连接池可以设置最大和最小连接,连接等待时间等,基本功能都有。
这个连接池的配置参见附件压缩包中的:c3p0.xml。
使用评价:在具体项目应用中,发现此连接池的持续运行的稳定性相当不错,在大并发量的压力下稳定性也有一定保证,
          此外不提供连接池监控。
          
3 proxool
proxool这个连接池可能用到的人比较少,但也有一定知名度,这个连接池可以设置最大和最小连接,连接等待时间等,基本功能都有。

 

public static Connection getC3p0Connection() {
  // TODO Auto-generated method stub
  ComboPooledDataSource ds = new ComboPooledDataSource();
  Connection conn = null;

 

  try {
   // 连接数据库常用属性设置
   ds.setDriverClass(DRIVER);
   ds.setJdbcUrl(URL);
   ds.setUser(USER);
   ds.setPassword(PSD); 
   // 设置连接池常用属性
   ds.setInitialPoolSize(2); // 初始连接个数
   ds.setMinPoolSize(1); // 最小连接数
   ds.setMaxPoolSize(10); // 最大连接数
   ds.setAcquireIncrement(5); // 当连接池中的连接被用完,再创建5个
   //ds.setCheckoutTimeout(120); // 设置过期时间,以秒为单位,如果连接池中
          // -处于空闲状态的连接超过了这个时间,该连接就会从连接池中删除
   ds.setMaxIdleTime(60); // 最大等待时间
   

 

   conn = ds.getConnection();
  } catch (SQLException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (PropertyVetoException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return conn;

}

}

 

 

 

以上是关于java编程中你偶遇过的池的主要内容,如果未能解决你的问题,请参考以下文章

13-Mixly中你可能没用过的数学运算(第1部分) | Mixly技巧系列

深度分析:那些Java中你一定遇到过的问题,一次性帮你搞定!深度分析:那些Java中你一定遇到过的问题,一次性帮你搞定!

Java 8中你可能没听过的10个新特性

深度分析:那些Java中你一定遇到过的问题,一次性帮你搞定!

Java线程的5个使用技巧

java中你确定用对单例了吗?