Tomcat7 新的数据库连接池Tomcat jdbc pool介绍和配置

Tomcat 在 7.0 以前的版本都是使用commons-dbcp做为连接池的实现,但是 dbcp存在一些问题:
(1)dbcp 是单线程的,为了保证线程安全会锁整个连接池
(2)dbcp 性能不佳
(3)dbcp 太复杂,超过 60 个类,发展滞后。
因此,通常J2EE中还会使用其它的高性能连接池,如C3P0,还有阿里系的druid 等。为此,Tomcat 从 7.0 开始引入一个新的模块:Tomcat jdbc pool
 tomcat jdbc pool 近乎兼容 dbcp ,性能更高
异步方式获取连接
tomcat jdbc pool 是 tomcat 的一个模块,基于 tomcat JULI,使用 Tomcat 的日志框架
使用 javax.sql.PooledConnection 接口获取连接
支持高并发应用环境
超简单,核心文件只有8个,比 c3p0 还少
更好的空闲连接处理机制
支持 JMX
支持 XA Connection。
tomcat jdbc pool 可在 Tomcat 中直接使用,也可以在独立的应用中使用。

阅读剩余部分...

JavaFX2 中CSS使用的几个问题总结

1.javaFx中引入CSS报错
使用如下代码
scene.getStylesheets().add(this.getClass().getResource("login.css").toExternalForm());
为JavaFX引入CSS,结果报
Exception in Application start method Exception in thread "main" java.lang.RuntimeException: Exception in Application start method at com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source).
....
Caused by: java.lang.NullPointerException

很明显,这样的问题是由于CSS文件找不到造成的。很可能是由于你的IDE不会自动把CSS文件从工程的SRC目录拷贝到build目录造成的。可以手工拷贝一下,或者清理项目重新生成。
参考网址:http://stackoverflow.com/questions/9862113/javafx-2-0-xychart-and-css

2..javaFx中引入CSS无效果
症状描述:使用代码
scene.getStylesheets().add(this.getClass().getResource("login.css").toExternalForm());

引入CSS,没有报错,但是也没有CSS效果,而是用下面的方式却是可行的:
grid.setStyle("-fx-background-image: url(\"ThghN.png\"); -fx-background-repeat: stretch; -fx-background-size: 300 250;");
问题原因:(1)可能你是用的是较早的javaFx版本,这是其中的一个BUG,解决办法就是升级版本(相关帖子:https://forums.oracle.com/forums/thread.jspa?threadID=2229859)。
(2)还有可能的原因就是CSS写错了。注意CSS中,选择器是.root,而不是root。在使用IDE生成代码时容易忽略,这个小问题害我排查了将近两个多小时。。。郁闷了
javaFx_css.png

最后,附上手册地址:http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html

java.util.Arrays的排序分享

java.uti.Arrays 包含用来操作数组(比如排序和搜索)的各种方法。这篇文章我们就来研究一些大师们写的排序算法。

(1) 基本数据类型数组的排序,如Arrays.sort(int[])等。采用了一种经过调优的快速排序。该算法改编自 Jon L. Bentley 和 M. Douglas McIlroy 合著的 Engineering a Sort Function", Software-Practice and Experience Vol. 23(11) P. 1249-1265 (November 1993)。此算法在许多数据集上提供 n*log(n) 性能,这导致其他快速排序会降低二次型性能。
下面是JDK中调优快速排序算法的源代码:

   /**
     * 将指定范围的整形数组升序排序。
     * x[] 待排数组
     * off 从数组的第off个元素开始排序
     * len 数组长度
     */
    private static void sort1(int x[], int off, int len) {
 //优化1:在小规模(size<7)数组中,直接插入排序的效率要比快速排序高。
 if (len < 7) {
     for (int i=off; i<len+off; i++)
      for (int j=i; j>off && x[j-1]>x[j]; j--)
       swap(x, j, j-1);
     return;
 }

 //优化2:精心选择划分元素,即枢轴
 //如果是小规模数组(size<=7),直接取中间元素作为枢轴
 //如果是中等规模数组(7=<size<=40),则在数组首、中、尾三个位置上的数中取中间大小的数作为枢轴
 //如果是大规模数组(size>40),则在9个指定的数中取一个伪中数(中间大小的数s)
 int m = off + (len >> 1);
 if (len > 7) {
     int l = off;
     int n = off + len - 1;
     if (len > 40) {       
   int s = len/8;
   l = med3(x, l, l+s, l+2*s);
   m = med3(x, m-s,   m,   m+s);
   n = med3(x, n-2*s, n-s, n);
     }
     m = med3(x, l, m, n);
 }
 int v = x[m];

         //优化3:每一次枢轴v的划分,都会形成形成一个形如  (<v)* v* (>v)*
        //阶段一,形成 v* (<v)* (>v)* v* 的数组
        int a = off, b = a, c = off + len - 1, d = c;
        while(true) {
     while (b <= c && x[b] <= v) {
   if (x[b] == v)
       swap(x, a++, b);
   b++;
     }
     while (c >= b && x[c] >= v) {
   if (x[c] == v)
       swap(x, c, d--);
   c--;
     }
     if (b > c)
      break;
     swap(x, b++, c--);
 }

 //阶段二,将枢轴和与枢轴相等的元素交换到数组中间
 int s, n = off + len;
 s = Math.min(a-off, b-a  );  vecswap(x, off, b-s, s);
 s = Math.min(d-c,   n-d-1);  vecswap(x, b,   n-s, s);

 //阶段三,递归排序与枢轴不相等都元素区间
 if ((s = b-a) > 1)
     sort1(x, off, s);
 if ((s = d-c) > 1)
     sort1(x, n-s, s);
    }


★ 优化1:在小规模(size<7)数组中,直接插入排序的效率要比快速排序高。

      没有一种排序在任何情况下都是最优的《基于比较的内部排序总结 》。 O(N^2)级别的排序看起来似乎比所有先进排序要差的多。但实际上也并非如此,Arrays中的sort()算法就给了我们一个很好的例子。当待排数组规模非常小的时候(JDK中规模的阈值为INSERTIONSORT_THRESHOLD=7),直接插入排序反而要比快排,归并排序要好。

    这个道理很简单。数组规模小,简单算法的比较次数不会比先进算法多多少。相反,诸如快排,归并排序等先进算法使用递归操作,所付出的运行代价更高。

阅读剩余部分...

转:hotspot内部对synchronize的实现

背景:
Java语言相较于c,c++的一个优势,是其从语言层面就提供了对多线程同步以及相互协作的支持;而不像c,c++,要通过其他的库才能写多线程程序。在Java语言里,通过synchronize关键字来同步一段关键代码片断(critical area),而通过wait,notify来实现线程间相互协作。本文主要描述一下sun的hotspot是如何来支持synchronize及wait和notify的。

在hotspot的实现里,每个java对象有一个对应的c++对象,每个用来表达java对象的c++对象都有一个header,占用2个word,第一个word成为mark word,第二个word则用来指向一个klass,该klass用来表征该对象的类型信息。第一个mark word,在某些情况下会用来表示同步信息,所以需要我们重点探究一下。


mark word是用来表征对象一些信息的对象头,目前依据jvm是32位还是64位,而分为32位64位2种形式。由于2者差别不大,所以我们这里以32位为例子,来讲解一下mark word。
在32位jvm上,markword为32位长,根据具体各个bit的数值的不同,可以组合成4种大类(表明该头markword所在的对象当前的状态),具体如下图所示。

我们现在需要关注的是前2类,即当markword表示该对象一个普通java对象或者被biased locking的对象。

2.hotspot当前对synchronize的实现类型及其应用场景
当前的hotspot共有3种类型的锁,来实现synchronize的语义,之所以有3种,是因为这3种要解决的问题不同,所做的优化也不同。这3种锁分别为biased locking,stack lock,infalted(ObjectMonitor).简单除暴的来讲,从轻量级上来说,biased lock最优,inflated 最差。

为了便于大家的认知,先从优化做的最少的Infalte锁开始讲起。

阅读剩余部分...

转:非主流并发工具之 ForkJoinPool

ForkJoinPool 是 Java SE 7 新功能“分叉/结合框架”的核心类,现在可能乏人问津,但我觉得它迟早会成为主流。分叉/结合框架是一个比较特殊的线程池框架,专用于需要将一个任务不断分解成子任务(分叉),再不断进行汇总得到最终结果(结合)的计算过程。比起传统的线程池类 ThreadPoolExecutorForkJoinPool 实现了工作窃取算法,使得空闲线程能够主动分担从别的线程分解出来的子任务,从而让所有的线程都尽可能处于饱满的工作状态,提高执行效率。

ForkJoinPool 提供了三类方法来调度子任务:

execute 系列
异步执行指定的任务。
invokeinvokeAll
执行指定的任务,等待完成,返回结果。
submit 系列
异步执行指定的任务并立即返回一个 Future 对象。

子任务由 ForkJoinTask 的实例来代表。它是一个抽象类,JDK 为我们提供了两个实现:RecursiveTaskRecursiveAction,分别用于需要和不需要返回计算结果的子任务。ForkJoinTask 提供了三个静态的 invokeAll 方法来调度子任务,注意只能在 ForkJoinPool 执行计算的过程中调用它们。

ForkJoinPoolForkJoinTask 还提供了很多让人眼花缭乱的公共方法,其实它们大多数都是其内部实现去调用的,对于应用开发人员来说意义不大。

下面以统计 D 盘某文件夹文件个数为例。这实际上是对一个文件树的遍历,我们需要递归地统计每个目录下的文件数量,最后汇总,非常适合用分叉/结合框架来处理:

   让人围观的是,这并不比单线程的Files.walkFileTree(...)
refer:http://www.blogjava.net/shinzey/archive/2012/02/09/368312.html

转:JVM伪共享

   伪共享False sharing说明JVM底层技术也不让人那么放心。

内存缓存系统中基本单元是高速缓存行(Cache lines). cpu会把数据从内存加载到高速缓存中 ,这样可以获得更好的性能,高速缓存默认大小是64 Byte为一个区域,一个区域在一个时间点只允许一个核心操作,也就是说不能有多个核心同时操作一个缓存区域。

因为高速缓存是64字节,而Hotspot JVM的对象头是两个部分组成,第一部分是由24字节的hash code和8字节的锁等状态标识组成,第二部分是指向该对象类的引用。基本类型字节如下:
doubles (8) and longs (8)
ints (4) and floats (4)
shorts (2) and chars (2)
booleans (1) and bytes (1)
references (4/8)

因此,一个高速缓存64字节可以放下多个字段,如果这多个字段位于同一个高速缓存区,虽然它们是类的不同字段,如下代码:
Class A{
   int x;
   int y;
}
x和y被放在同一个高速缓存区,如果一个线程修改x;那么另外一个线程修改y,必须等待x修改完成后才能实施。
虽然两个线程修改各种独立变量,但是因为这些独立变量被放在同一个高速缓存区,性能就影响了。测试结果如后面。
当多核CPU线程同时修改在同一个高速缓存行各自独立的变量时,会不自不觉地影响性能,这就发生了伪共享False sharing,伪共享是性能的无声杀手。

解决方便是将高速缓存剩余的字节填充填满(pad),确保不发生多个字段被挤入一个高速缓存区,下面测试结果图就是和填充后性能比较。

实现字节填充的框架有 Disruptor,在RingBuffer中实现填充。关于Disruptor可见infoQ这个视频,用1毫秒的延时得到100K+ TPS吞吐量,JDK的ArrayQueue并行环境不见得是最快的,该视频后面讨论很多,让人大跌眼镜啊,开放源码多有好处啊,别人能发现你不能发现的漏洞。另外一篇解剖Disruptor

C#也有类似伪共享发生,见这里
jvm_False_sharing.png
参考:http://www.jdon.com/jivejdon/thread/42451
LMAX架构
disruptor - 并发编程框架
http://www.infoq.com/presentations/LMAX

转:正确使用 Volatile 变量

简介: Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。在这期的Java 理论与实践中,Brian Goetz 将介绍几种正确使用 volatile 变量的模式,并针对其适用性限制提出一些建议。

       Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。本文介绍了几种有效使用 volatile 变量的模式,并强调了几种不适合使用 volatile 变量的情形。

锁提供了两种主要特性:互斥(mutual exclusion)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题。

Volatile 变量

Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式(Invariants)的类(例如 “start <=end”)。

出于简易性或可伸缩性的考虑,您可能倾向于使用 volatile 变量而不是锁。当使用 volatile 变量而非锁时,某些习惯用法(idiom)更加易于编码和阅读。此外,volatile 变量不会像锁那样造成线程阻塞,因此也很少造成可伸缩性问题。在某些情况下,如果读操作远远大于写操作,volatile 变量还可以提供优于锁的性能优势。

正确使用 volatile 变量的条件

您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:


  • 对变量的写操作不依赖于当前值。
  • 该变量没有包含在具有其他变量的不变式中。

实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。

第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x 的值在操作期间保持不变,而 volatile 变量无法实现这点。(然而,如果将值调整为只从单个线程写入,那么可以忽略第一个条件。)

大多数编程情形都会与这两个条件的其中之一冲突,使得 volatile 变量不能像 synchronized 那样普遍适用于实现线程安全。清单 1 显示了一个非线程安全的数值范围类。它包含了一个不变式 —— 下界总是小于或等于上界。


清单 1. 非线程安全的数值范围类
@NotThreadSafe
public class NumberRange {
private int lower, upper;

public int getLower() { return lower; }
public int getUpper() { return upper; }

public void setLower(int value) {
if (value > upper)
throw new IllegalArgumentException(...);
lower = value;
}

public void setUpper(int value) {
if (value < lower)
throw new IllegalArgumentException(...);
upper = value;
}
}

    

阅读剩余部分...

转:指令重排序与happens-before法则

Java Concurrency in Practice中是这样定义线程安全的:



显然只有资源竞争时才会导致线程不安全,因此

原子操作的描述是: 多个线程执行一个操作时,其中,那么这个操作就是原子的。

枯燥的定义介绍完了,下面说更枯燥的理论知识。

Java语言规范规定了JVM线程内部维持顺序化语义,也就是说只要程序的最终结果等同于它在严格的顺序化环境下的结果,那么指令的执行顺序就可能与代码的顺序不一致。这个过程通过叫做指令的重排序。指令重排序存在的意义在于:JVM能够根据处理器的特性(CPU的多级缓存系统、多核处理器等)适当的重新排序机器指令,使机器指令更符合CPU的执行特点,最大限度的发挥机器的性能。

程序执行最简单的模型是按照指令出现的顺序执行,这样就与执行指令的CPU无关,最大限度的保证了指令的可移植性。这个模型的专业术语叫做顺序化一致性模型。但是现代计算机体系和处理器架构都不保证这一点(因为人为的指定并不能总是保证符合CPU处理的特性)。

我们来看最经典的一个案例。

阅读剩余部分...

    Page :
  1. 1
  2. 2
  3. 3
  4. 4
  5. ...
  6. 7