#
线程的同步是保证多线程安全访问竞争资源的一种手段。
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?
在本文之前,请参阅《Java线程:线程的同步与锁》,本文是在此基础上所写的。
对于同步,在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。
synchronized关键字使用说明
synchronized只能标记非抽象的方法,不能标识成员变量。
为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。
/**
* Java线程:线程的同步
*
* @author leizhimin 2009-11-4 11:23:32
*/
public class Test {
public static void main(String[] args) {
User u = new User("张三", 100);
MyThread t1 = new MyThread("线程A", u, 20);
MyThread t2 = new MyThread("线程B", u, -60);
MyThread t3 = new MyThread("线程C", u, -80);
MyThread t4 = new MyThread("线程D", u, -30);
MyThread t5 = new MyThread("线程E", u, 32);
MyThread t6 = new MyThread("线程F", u, 21);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class MyThread extends Thread {
private User u;
private int y = 0;
MyThread(String name, User u, int y) {
super(name);
this.u = u;
this.y = y;
}
public void run() {
u.oper(y);
}
}
class User {
private String code;
private int cash;
User(String code, int cash) {
this.code = code;
this.cash = cash;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 业务方法
* @param x 添加x万元
*/
public synchronized void oper(int x) {
try {
Thread.sleep(10L);
this.cash += x;
System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash);
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "User{" +
"code='" + code + '\'' +
", cash=" + cash +
'}';
}
}
输出结果:
线程A运行结束,增加“20”,当前用户账户余额为:120
线程F运行结束,增加“21”,当前用户账户余额为:141
线程E运行结束,增加“32”,当前用户账户余额为:173
线程C运行结束,增加“-80”,当前用户账户余额为:93
线程B运行结束,增加“-60”,当前用户账户余额为:33
线程D运行结束,增加“-30”,当前用户账户余额为:3
Process finished with exit code 0
反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下:
线程A运行结束,增加“20”,当前用户账户余额为:61
线程D运行结束,增加“-30”,当前用户账户余额为:63
线程B运行结束,增加“-60”,当前用户账户余额为:3
线程F运行结束,增加“21”,当前用户账户余额为:61
线程E运行结束,增加“32”,当前用户账户余额为:93
线程C运行结束,增加“-80”,当前用户账户余额为:61
Process finished with exit code 0
很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,
tb并对u的属性做了改动。
可见同步的重要性。
注意:
通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于java.lang.Object类。
void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
void wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
结合以上方法,处理多线程同步与互斥问题非常重要,著名的生产者-消费者例子就是一个经典的例子,任何语言多线程必学的例子。
摘要: 本篇博文讲两件事情,一个是推荐在博客园经常写博客的童鞋们一个很棒的工具--“百度统计”,另一个是“拷贝百度统计”的页面框架。
首先讲第一个事情,我的博客里有不少文章都是讲“用户行为分析”的,虽然现在不做这个方向的项目,但是对它的兴趣不减,所以我今天在自己博客里部署了百度的用户行为分析系统“百度统计̶...
阅读全文
对1.0版进行了重构,去掉了一些花销的功能,优化了页面样式,现有功能:
1)、一次性把数据加载到页面内存,在页面进行分页。
2)、使用jquery的ajax每次从服务器取数据分页。
3)、支持自定义分页条样式,插件默认实现两种样式可供选择。
- <table id="table2" >
- <thead>
- <tr><th width="200px">网站名称</th>
- <th width="100px">网址</th>
- <th width="100px">知名度</th>
- <th width="120px">访问量</th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
-
- $("#table2").bigPage({ajaxData:{url:"ajax.php"}});
<table id="table2" >
<thead>
<tr><th width="200px">网站名称</th>
<th width="100px">网址</th>
<th width="100px">tb知名度</th>
<th width="120px">访问量</th>
</tr>
</thead>
<tbody></tbody>
</table>
$("#table2").bigPage({ajaxData:{url:"ajax.php"}});
更多的例子及代码下载地址:
http://bigui4.sinaapp.com/index.html
摘要: 简介
Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不同的数据访问技术,如JDBC,Hibernate或者JDO等。它不仅可以让你方便地在这些持久化技术间切换, 而且让你在编码的时候不用考虑处理各种技术中特定的异常。
一致的异常层次
Spring提供了一种方便的方法,把特定于某种技术的异常,如SQLException, 转化为自己的异常,这种异常属于以 ...
阅读全文
目前,最常用的三种动态网页语言有ASP(Active Server Pages),JSP(JavaServer Pages),PHP (Hypertext Preprocessor)。
简 介 :
ASP全名Active Server Pages,是一个WEB服务器端的开发环境,利用它可以产生和执行动态的、互动的、高性能的WEB服务应用程序
(1)ASP采用脚本语言VBScript(Java script)作为自己的开发语言。
(2)PHP是一种跨平台的服务器端的嵌入式脚本语言。它大量地借用C, Java和Perl语言的语法, 并耦合PHP自己的特性,使WEB开发者能够快速地写出动态产生页面。它支持目前绝大多数数据库。还有一点,PHP是完全免费的,不用花钱,你可以从PHP官方站点(http: //www.php.net)自由下载。而且你可以不受限制地获得源码,甚至可以从中加进你自己需要的特色。
(3)JSP是Sun公司推出的新一代网站开发语言,Sun公司借助自己在Java上的不凡造诣,将Java从Java应用程序和Java Applet之外,又有新的硕果,就是JSP,Java Server Page。JSP可以在Serverlet和JavaBean的支持下,完成功能强大的站点程序。
三者都提供在 HTML代码中混合某种程序代码、由语言引擎解释执行程序代码的能力。但JSP代码被编译成 Servlet并由Java虚拟机解释执行,这种编译操作仅在对JSP页面的第一次请求时发生。在ASP 、PHP、JSP环境下,HTML代码主要负责描述信息的显示样式,而程序代码则用来描述处理逻辑。普通的 HTML页面只依赖于Web服务器,而ASP 、PHP、JSP页面需要附加的语言引擎分析和执行程序代码。程序代码的执行结果被重新嵌入到HTML代码中,然后一起发送给浏览器。ASP 、PHP、JSP三者都是面向Web服务器的技术,客户端浏览器不需要任何附加的软件支持。
技术特点
ASP:
1. 使用VBScript 、 JScript等简单易懂的脚本语言,结合HTML代码,即可快速地完成网站的应用程序。
2. 无须compile编译,容易编写,可在服务器端直接执行。
3. 使用普通的文本编辑器,如Windows的记事本,即可进行编辑设计。
4. 与浏览器无关(Browser Independence), 客户端只要使用可执行HTML码的浏览器,即可浏览Actbive Server Pages所设计的网页内容。Active ServerPages 所使用的脚本语言(VBScript 、 Jscript)均在WEB服务器端执行,客户端的浏览器不需要能够执行这些脚本语言。
5.Active Server Pages能与任何ActiveX scripting语言兼容。除了可使用VB Script或JScript语言来设计外,还通过plug-in的方式,使用由第三方所提供的其它脚本语言,譬如REXX 、Perl 、Tcl等。脚本引擎是处理脚本程序的COM(Component Object Model) 对象。
6. 可使用服务器端的脚本来产生客户端的脚本。
7. ActiveX Server Components(ActiveX 服务器组件 )具有无限可扩充性。可以使用Visual Basic 、Java 、Visual C++ 、COBOL等程序设计语言来编写你所需要的ActiveX Server Component 。
PHP:
1. 数据库连接
PHP可以编译成具有与许多数据库相连接的函数。PHP与MySQL是现在绝佳的群组合。你还可以自己编写外围的函数去间接存取数据库。通过这样的途径当你更换使用的数据库时,可以轻松地修改编码以适应这样的变化。PHPLIB就是最常用的可以提供一般事务需要的一系列基库。但PHP提供的数据库接口支持彼此不统一,比如对Oracle, MySQL,Sybase的接口,彼此都不一样。这也是PHP的一个弱点。
JSP:
1. 将内容的产生和显示进行分离
使用JSP技术,Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使用JSP标识或者小脚本来产生页面上的动态内容。产生内容的逻辑被封装在标识和JavaBeans群组件中,并且捆绑在小脚本中,所有的脚本在服务器端执行。如果核心逻辑被封装在标识和Beans中,那么其它人,如Web管理人员和页面设计者,能够编辑和使用JSP页面,而不影响内容的产生。在服务器端,JSP引擎解释JSP标识,产生所请求的内容(例如,通过存取JavaBeans群组件,使用JDBC技术存取数据库),并且将结果以HTML(或者XML)页面的形式发送回浏览器。这有助于作者保护自己的代码,而又保证任何基于HTML的Web浏览器的完全可用性。
2. 强调可重用的群组件
绝大多数JSP页面依赖于可重用且跨平台的组件(如:JavaBeans或者Enterprise JavaBeans)来执行应用程序所要求的更为复杂的处理。开发人员能够共享和交换执行普通操作的组件,或者使得这些组件为更多的使用者或者用户团体所使用。基于组件的方法加速了总体开发过程,并且使得各种群组织在他们现有的技能和优化结果的开发努力中得到平衡。
3. 采用标识简化页面开发
Web页面开发人员不会都是熟悉脚本语言的程序设计人员。JavaServer Page技术封装了许多功能,这些功能是在易用的、与JSP相关的XML标识中进行动态内容产生所需要的。标准的JSP标识能够存取和实例化 JavaBeans组件,设定或者检索群组件属性,下载Applet,以及执行用其它方法更难于编码和耗时的功能。
通过开发定制化标识库,JSP技术是可以扩展的。今后,第三方开发人员和其它人员可以为常用功能建立自己的标识库。这使得Web页面开发人员能够使用熟悉的工具和如同标识一样的执行特定功能的构件来工作。
JSP技术很容易整合到多种应用体系结构中,以利用现存的工具和技巧,并且扩展到能够支持企业级的分布式应用。作为采用Java技术家族的一部分,以及Java 2EE的一个成员,JSP技术能够支持高度复杂的基于Web的应用。
由于JSP页面的内置脚本语言是基于Java程序设计语言的,而且所有的JSP页面都被编译成为Java Servlet,JSP页面就具有Java技术的所有好处,包括健壮的存储管理和安全性。
作为Java平台的一部分,JSP拥有Java程序设计语言“一次编写,各处执行”的特点。随着越来越多的供货商将JSP支持加入到他们的产品中,您可以使用自己所选择的服务器和工具,修改工具或服务器并不影响目前的应用。
应用范围
ASP是Microsoft开发的动态网页语言,也继承了微软产品的一贯传统,只能执行于微软的服务器产品,IIS(Internet Information Server)(windows NT)和PWS(Personal Web Server)(windows 98)上。Unix下也有ChiliSoft的组件来支持ASP,但是ASP本身的功能有限,必须通过ASP+COM的群组合来扩充,Unix下的COM实现起来非常困难。
PHP3可在Windows,Unix,Linux的Web服务器上正常执行,还支持IIS,Apache等一般的Web服务器,用户更换平台时,无需变换PHP3代码,可即拿即用。
JSP同PHP3类似,几乎可以执行于所有平台。如Win NT,Linux,Unix。在NT下IIS通过一个外加服务器,例如JRUN或者ServletExec,就能支持JSP。知名的Web服务器Apache已经能够支持JSP。由于Apache广泛应用在NT、Unix和Linux上,因此JSP有更广泛的执行平台。虽然现在NT操作系统占了很大的市场份额,但是在服务器方面Unix的优势仍然很大,而新崛起的Linux更是来势不小。从一个平台移植到另外一个平台,JSP和JavaBean甚至不用重新编译,因为Java字节码都是标准的与平台无关的。
性能比较
有人做过试验,对这三种语言分别做回圈性能测试及存取Oracle数据库测试。
在循环性能测试中,JSP只用了令人吃惊的四秒钟就结束了20000*20000的回圈。而ASP、PHP测试的是2000*2000循环(少一个数量级),却分别用了63秒和84秒。(参考PHPLIB)。
数据库测试中,三者分别对 Oracle 8 进行 1000 次 Insert,Update,Select和Delete: JSP 需要 13 秒,PHP 需要 69 秒,ASP则 需要73 秒。
前景分析
目前在国内PHP与ASP应用最为广泛。而JSP由于是一种较新的技术,国内采用的较少。但在国外,JSP已经是比较流行的一种技术,尤其是电子商务类的网站,多采用JSP。
采用PHP的网站如新浪网(sina)、中国人(Chinaren)等,但由于PHP本身存在的一些缺点,使得它不适合应用于大型电子商务站点,而更适合一些小型的商业站点。首先,PHP缺乏规模支持。其次,缺乏多层结构支持。对于大负荷站点,解决方法只有一个:分布计算。数据库、应用逻辑层、表示逻辑层彼此分开,而且同层也可以根据流量分开,群组成二维数组。而PHP则缺乏这种支持。还有上面提到过的一点,PHP提供的数据库接口支持不统一,这就使得它不适合运用在电子商务中。
ASP和JSP则没有以上缺陷,ASP可以通过Microsoft Windowsd的COM/DCOM获得ActiveX规模支持,通过DCOM和Transcation Server获得结构支持;JSP可以通过SUN Java的Java Class和EJB获得规模支持,通过EJB/CORBA以及众多厂商的Application Server获得结构支持。
三者中,JSP应该是未来发展的趋势。世界上一些大的电子商务解决方案提供商都采用JSP/Servlet。比较出名的如IBM的E-business,它的核心是采用JSP/Servlet的Web Sphere。它们都是通过CGI来提供支持的。但去年10月后它推出了Enfinity,一个采用JSP/Servlet的电子商务Application Server,而且声言不再开发传统软件。
总之,ASP,PHP,JSP三者都有相当数量的支持者,由此也可以看出三者各有所长。正在学习或使用动态页面的朋友可根据三者的特点选择一种适合自己的语言。
1、数据库当中的表设计
2、对应数据表的实体Bean (id为主键)
- public class EnginConfigVO {
- int id = 0;
- int THREADS_COUNT;
-
-
-
-
- public int primaryGetId() {
- return id;
- }
-
-
-
- public void primarySetId(int id) {
- this.id = id;
- }
-
-
-
- public int getTHREADS_COUNT() {
- return THREADS_COUNT;
- }
-
-
-
-
- public void setTHREADS_COUNT(int tHREADS_COUNT) {
- THREADS_COUNT = tHREADS_COUNT;
- }
- }
public class EnginConfigVO {
int id = 0;
int THREADS_COUNT;
/**
* @return the id
*/
public int primaryGetId() {
return id;
}
/**
* @param id the id to set
*/
public void primarySetId(int id) {
this.id = id;
}
/**
* @return the tHREADS_COUNT
*/
public int getTHREADS_COUNT() {
return THREADS_COUNT;
}
/**
* @param tHREADS_COUNT the tHREADS_COUNT to set
*/
public void setTHREADS_COUNT(int tHREADS_COUNT) {
THREADS_COUNT = tHREADS_COUNT;
}
}
由于没有像hibernate那样的注解机制,所以只能在主键的setter和getter方法上动动手脚primaryGetId() ,primarySetId(int id)
而实体bean的类名在与数据表的匹配上最后多了“vo” 两个字母,所以在tb下面方法中将这两个字母剪裁掉。
反射方法:
T o 对应的就是实体Bean,这样的方法当然是写在DAO层中,供上层的service调用,传入需要修改的实体Bean
- public <T> void updatePropertiesValues(T o) {
- StringBuilder sd = new StringBuilder("update ");
- sd.append(o.getClass().getSimpleName().toLowerCase().substring(0, o.getClass().getSimpleName().length()-2)).append(" ");
- sd.append("set ");
- StringBuilder id = new StringBuilder("where ");
- try {
- for(Method m : o.getClass().getDeclaredMethods()) {
- String name = m.getName();
- if (name.startsWith("get")) {
- sd.append(name.substring(3).toLowerCase()).append("=");
- if(m.invoke(o) instanceof String) {
- sd.append("'").append(m.invoke(o)).append("', ");
- }else {
- sd.append(m.invoke(o)).append(", ");
- }
- }
- if(name.startsWith("primaryGet")) {
- id.append(name.substring(10).toLowerCase()).append("=");
- if(m.invoke(o) instanceof String) {
- id.append("'").append(m.invoke(o)).append("';");
- }else {
- id.append(m.invoke(o)).append(";");
- }
- }
- }
- sd.delete(sd.length()-2, sd.length());
- sd.append(" ");
- sd.append(id);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
-
- executeTrans(sd.toString());
-
- }
public <T> void updatePropertiesValues(T o) {
StringBuilder sd = new StringBuilder("update ");
sd.append(o.getClass().getSimpleName().toLowerCase().substring(0, o.getClass().getSimpleName().length()-2)).append(" ");
sd.append("set ");
StringBuilder id = new StringBuilder("where ");
try {
for(Method m : o.getClass().getDeclaredMethods()) {
String name = m.getName();
if (name.startsWith("get")) {
sd.append(name.substring(3).toLowerCase()).append("=");
if(m.invoke(o) instanceof String) {
sd.append("'").append(m.invoke(o)).append("', ");
}else {
sd.append(m.invoke(o)).append(", ");
}
}
if(name.startsWith("primaryGet")) {
id.append(name.substring(10).toLowerCase()).append("=");
if(m.invoke(o) instanceof String) {
id.append("'").append(m.invoke(o)).append("';");
}else {
id.append(m.invoke(o)).append(";");
}
}
}
sd.delete(sd.length()-2, sd.length());
sd.append(" ");
sd.append(id);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
executeTrans(sd.toString());
}
这样以后便可以拼凑出完整的sql语句,为我们解决了功能相似代码的冗余。。
另外在查找时,我们还可以利用发射机制,将数据库返回的resultset 对象包装成List<T>
- public static <T> List<T> getObjectsList(ResultSet rs, Class<T> k)
- throws SQLException {
- List<T> bl = new ArrayList<T>();
- if (rs != null) {
- while (rs.next()) {
-
- T o = null;
- try {
- o = k.newInstance();
- for (Method m : k.getDeclaredMethods()) {
- String name = m.getName();
- if (name.startsWith("set")) {
-
- m.invoke(o, rs.getObject(name.substring(3)));
- }
- }
- bl.add(o);
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- return bl;
- }
- return null;
- }
public static <T> List<T> getObjectsList(ResultSet rs, Class<T> k)
throws SQLException {
List<T> bl = new ArrayList<T>();
if (rs != null) {
while (rs.next()) {
// System.out.println("result is not null");
T o = null;
try {
o = k.newInstance();
for (Method m : k.getDeclaredMethods()) {
String name = m.getName();
if (name.startsWith("set")) {
// System.out.println(rs.getObject(name.substring(3)).getClass().getName());
m.invoke(o, rs.getObject(name.substring(3)));
}
}
bl.add(o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return bl;
}
return null;
}
这样,我们就可以从底层直接获得包装好的List<T>集合。。不足之处,欢迎大家讨论。。
java 单例加锁方法:
ScheduleEngine是个单例类,在获得实例的方法getinstance中,两次判断其是否为空,有利于多线程的并发操作。
使得实例化时,只在第一次加锁,这样效率会有提高。
- class ScheduleEngine{
-
- private static Lock instanceLock=new ReentrantLock();
-
- private ScheduleEngine() {
- setproperties;
- }
-
- public static ScheduleEngine getInstance(int temphandlerType) {
- if(null==engine) {
- instanceLock.lock();
- try
- {
- if(null==engine)
- {
- handlerType=temphandlerType;
- engine=new ScheduleEngine(temphandlerType);
- }
-
- }
- finally
- {
- instanceLock.unlock();
- }
- }
- return engine;
- }
- }
class ScheduleEngine{
private static Lock instanceLock=new ReentrantLock();
private ScheduleEngine() {
setproperties;
}
public static ScheduleEngine getInstance(int temphandlerType) {
if(null==engine) {
instanceLock.lock();
try
{
if(null==engine)
{
handlerType=temphandlerType;
engine=new ScheduleEngine(temphandlerType);
}
}
finally
{
instanceLock.unlock();
}
}
return engine;
}
}
初始实例化 单例c3p0对象的方法,常用的是
public final class ConnectionManager {
private static ConnectionManager instance;
private static ComboPooledDataSource cpds;
private static String c3p0Properties;
/**
* 从数据库连接池取连接
* @throws Exception
*/
private ConnectionManager() throws Exception {
Properties p = new Properties();
c3p0Properties = System.getProperty("user.dir") +
"/mom_project_config/database.properties";
// p.load(this.getClass().getClassLoader().getResourceAsStream(c3p0Properties));
p.load(new BufferedInputStream(new FileInputStream(c3p0Properties)));
// String url = p.getProperty("url") + p.getProperty("database");
String url = p.getProperty("url") + p.getProperty("database")+"?useUnicode=true&characterEncoding=UTF-8";
cpds = new ComboPooledDataSource();
cpds.setDriverClass(p.getProperty("driverclass"));
cpds.setJdbcUrl(url);
cpds.setUser(p.getProperty("user"));
cpds.setPassword(p.getProperty("password"));
// 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 acquireIncrement
cpds.setAcquireIncrement(Integer.valueOf(p
.getProperty("acquireincrement")));
// 定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 acquireRetryAttempts
cpds.setAcquireRetryAttempts(Integer.valueOf(p
.getProperty("acquireretryattempts")));
// 两次连接中间隔时间,tb单位毫秒。Default: 1000 acquireRetryDelay
cpds.setAcquireRetryDelay(Integer.valueOf(p
.getProperty("acquireretrydelay")));
// 自动提交事务;连接关闭时默认将所有未提交的操作回滚。Default: false autoCommitOnClose
cpds.setAutoCommitOnClose(Boolean.valueOf(p
.getProperty("autocommitonclose")));
// 当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,
// 如设为0则无限期等待.单位毫秒,默认为0
cpds.setCheckoutTimeout(Integer.valueOf(p
.getProperty("checkouttimeout")));
// 每多少秒检查所有连接池中的空闲连接。默认为0表示不检查。Default: 0 idleConnectionTestPeriod
cpds.setIdleConnectionTestPeriod(Integer.valueOf(p
.getProperty("idleconnectiontestperiod")));
// 最大空闲时间,25000秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 maxIdleTime
cpds.setMaxIdleTime(Integer.valueOf(p.getProperty("maxidletime")));
// 初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 initialPoolSize
cpds.setInitialPoolSize(Integer.valueOf(p
.getProperty("initialpoolsize")));
// 连接池中保留的最小连接数。
cpds.setMinPoolSize(Integer.valueOf(p.getProperty("minpoolsize")));
// 连接池中保留的最大连接数。Default: 15 maxPoolSize
cpds.setMaxPoolSize(Integer.valueOf(p.getProperty("maxpoolsize")));
// JDBC的标准参数,用以控制数据源内加载的PreparedStatement数据.但由于预缓存的Statement属于单个Connection而不是整个连接池.所以
// 设置这个参数需要考滤到多方面的因素,如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭.默认为0;
cpds.setMaxStatements(Integer.valueOf(p.getProperty("maxstatements")));
// 连接池内单个连接所拥有的最大缓存被关闭.默认为0;
cpds.setMaxStatementsPerConnection(Integer.valueOf(p
.getProperty("maxstatementsperconnection")));
// C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成.扩展这些操作可以有效的提升性能,通过多数程实现多个操作同时被执行.默为为3
cpds.setNumHelperThreads(Integer.valueOf(p
.getProperty("numhelperthreads")));
// 用户修改系统配置参数执行前最多等待的秒数.默认为300;
cpds.setPropertyCycle(Integer.valueOf(p.getProperty("propertycycle")));
// 如果设为true那么在取得连接的同时将校验连接的有效性。Default: false testConnectionOnCheckin
cpds.setTestConnectionOnCheckin(Boolean.valueOf(p
.getProperty("testconnectiononcheckin")));
// 因性能消耗大请只在需要的时候使用它。
// 如果设为true那么在每个connection提交的时候都将校验其有效性。
// 建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default:
// false testConnectionOnCheckout
cpds.setTestConnectionOnCheckout(Boolean.valueOf(p
.getProperty("testconnectionOncheckout")));
// 获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。
// 但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。
// 如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false
// breakAfterAcquireFailure
cpds.setBreakAfterAcquireFailure(Boolean.valueOf(p
.getProperty("breakafteracquirefailure")));
}
/**
* 获得ConnectionManager单例对象
* @return
*/
public synchronized static ConnectionManager getInstance() {
if (instance == null) {
try {
instance = new ConnectionManager();
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
/**
* 获得连接
* @return
*/
public Connection getContection() {
try {
return cpds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
在初始化获得单例的方法上面加锁,不利于并发操作的执行,用第一段代码两次判断是否为空的方式,可以减少代码执行中锁的引用。 不足之处烦请朋友们指正。。
Java在网络编程这个地方做的很好,java的主要目的也是为了网络而生的,它能方便的访问网络上的资源。我们这节课来介绍网络通讯的两种机制:URL通信机制,Socket通信机制。
URL表示了Internet上一个资源的引用或地址。Java网络应用程序也是使用URL来定位要访问的Internet的资源。在jdk里面java.net.URL也是一个类,它来封装URL的一些细节。目前大家可以把URL理解为网址,default.aspx 这就是个URL.http是协议名(超文本传输协议)用“://”隔开www.tbwshc.com 是主机名。Default.aspx是文件名。它的端口号没有写,默认是80.
实践:
import java.net.*;
public class ParseURL {
public static void main(String[] args) throws MalformedURLException{
URL url = new URL("http://www.100jq.com:45175/default.aspx");
System.out.println("协议是 "+url.getProtocol());
System.out.println("主机是 "+url.getHost());
System.out.println("文件名是 "+url.getFile());
System.out.println("端口号是 "+url.getPort());
}}
/*
URL这个对象中提供了很多方法像是
getProtocol()
getHost()
getFile()
getPort()
*/ |
我们可以通过URL对文件或资源读取,tb也可以通过URLConnection读取,也可以通过这个写入数据限于cgi脚本。
实践:
import java.net.*;
import java.io.*;
public class URLConnectionReader {
public static void main(String[] args) throws IOException {
URL google = new URL("");
URLConnection g = google.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(g.getInputStream()));
String inputLine;
while ((inputLine=in.readLine())!=null)
System.out.println(inputLine);
in.close();
}} |
URL和URLConnection类提供了较高层次的网络访问。有时候需要进行较低层次的访问。编写C/S模型的程序时,就要使用Socket通信机制了。因为在网络上不一定非得访问文件。
实践:
//先写个客户端的应用
import java.net.*;
import java.io.*;
public class SimpleClient {
public static void main(String args[]) {
try {
// 在5432端口打开服务器连接
// 在这里用localhost与127.0.0.1是一个意思
Socket s1 = new Socket("127.0.0.1", 5432);
// 对这个端口连接一个reader,注意端口不能够占用别的
BufferedReader br = new BufferedReader(
new InputStreamReader(s1.getInputStream()));
// 读取输入的数据并且打印在屏幕上
System.out.println(br.readLine());
//当完成时关闭流和连接
br.close();
s1.close();
} catch (ConnectException connExc) {
System.err.println("Could not connect to the server.");
} catch (IOException e) {
// ignore
}}}
//这是服务端的应用
import java.net.*;
import java.io.*;
public class SimpleServer {
public static void main(String args[]) {
ServerSocket s = null;
// 注册服务端口为5432
try {
s = new ServerSocket(5432);
} catch (IOException e) {
e.printStackTrace();
}
// 运行监听器并接收,永远循环下去。因为服务器总要开启的
while (true) {
try {
// 等待一个连接的请求
Socket s1 = s.accept();
// 得到端口的输出流
OutputStream s1out = s1.getOutputStream();
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s1out));
// 发送一个字符串
bw.write("百家拳软件项目研究室欢迎您!\n");
// 关闭这个连接, 但不是服务端的socket
bw.close();
s1.close();
} catch (IOException e) {
e.printStackTrace();
}}}} |
下载 href="http://java.chinaitlab.com/download/07072213182935.rar" target=_blank>上述例子打包下载
执行这个程序和其它的不太一样,先用javac将两个文件编译之后。然后敲start开启另一个窗口。用start命令开启的窗口继承了原来窗口的特性。如图26-1所示
图26-1
接着在原来的窗口上执行服务端程序java SimpleServer.在新窗口中执行java SimpleClient 就会看到结果了。注意如果如果在启动服务端的时候抛出bindException则说明5432这个端口已经被别的程序占用着,改成别的端口号就可以了。通常选用端口的时候,其数字最好不要小于1024,1024一下的端口很多都是专用的端口。
现在的java界,很多东西叫××let,××let的意思都是些小程序的意思。例如:applet应用程序的小程序,servlet服务器端的小程序,midlet手机中的小程序,portlet门户容器端的小程序。这节我们介绍applet.这个东西用的不是很多,但是在java的体系结构中是很有意义的。这个东西是能够在浏览器里运行的,可以潜入到HTML页面里。我们知道普通的Application要有main()作为入口点运行,而Applet要在浏览器里运行,或者开发时查看的时候用appletviewer运行。举个例子,实践:
import java.awt.*;
import java.applet.*;
@SuppressWarnings("serial") //抑制警告
//所有的Applet,都继承了java.applet.Applet
public class HelloApplet extends Applet {
public void paint(Graphics g){
g.drawString("百家拳软件项目研究室!",30,30);
}} |
还需要建立一个html文件,因为刚才说了它可以嵌入在浏览器里面。用记事本建立一个hello.html代码如下:
<applet code="HelloApplet.class" width=150 heightb=150></applet>
之后照样用javac编译刚才那个类。最后在命令行中输入appletviewer hello.html可以看到结果。
这种小程序弥补了B/S模型的不足,用浏览器可以执行客户端的东西。因为它功能强大,所以是个不错的东西。可是功能太强大了,又引发了一些安全性的问题。所以浏览器也会对applet做了一些安全性的限制。Applet还有一种叫做沙箱模型的机制,它使得没有访问权限的资源,不能访问。保证了安全性。同时开发时也不是那么方便。Applet又跨平台的特性。
而且微软的IE浏览器里面在运行applet的时候速度不是很快,不如activex的方便。界面也不是太漂亮。不过它的这种在浏览器中运行的思想还是比较不错的。
1 、对象的初始化
(1 )非静态对象的初始化
在创建对象时,对象所在类的所有数据成员会首先进行初始化。
基本类型:int 型,初始化为0.
如果为对象:这些对象会按顺序初始化。
※在所有类成员初始化完成之后,才调用本类的构造方法创建对象。
构造方法的作用就是初始化。
(2 )静态对象的初始化
程序中主类的静态变量会在main方法执行前初始化。
不仅第一次创建对象时,类中的所有静态变量都初始化,并且第一次访问某
类(注意此时未创建此类对象)的静态对象时,所有的静态变量也要按它们在类
中的顺序初始化。
2 、继承时,对象的初始化过程
(1 )主类的超类由高到低按顺序初始化静态成员,无论静态成员是否为private.
(2 )主类静态成员的初始化。
(3 )主类的超类由高到低进行默认构造方法的调用。注意,在调用每一个
超类的默认构造方法前,先进行对此超类进行非静态对象的初始化。
(4 )主类非静态成员的初始化。
(5 )调用主类的构造方法。
3 、关于构造方法
(1 )类可以没有构造方法,但如果有多个构造方法,就应该要有默认的构
造方法,否则在继承此类时,需要在子类中显式调用父类的某一个非默认的构造
方法了。
(2 )在一个构造方法中,只能调用一次其他的构造方法,并且调用构造方
法的语句必须是第一条语句。
4 、有关public、private 和protected
(1 )无public修饰的类,可以被其他类访问的条件是:a.两个类在同一文
件中,b.两个类在同一文件夹中,c.两个类在同一软件包中。
(2 )protected :继承类和同一软件包的类可访问。
(3 )如果构造方法为private ,那么在其他类中不能创建该类的对象。
5 、抽象类
(1 )抽象类不能创建对象。
(2 )如果一个类中一个方法为抽象方法,则这个类必须为abstract抽象类。
(3 )继承抽象类的类在类中必须实现抽象类中的抽象方法。
(4 )抽象类中可以有抽象方法,也可有非抽象方法。抽象方法不能为private.
(5 )间接继承抽象类的类可以不给出抽象方法的定义。
6 、final 关键字
(1 )一个对象是常量,不代表不能转变对象的成员,仍可以其成员进行操
作。
(2 )常量在使用前必须赋值,但除了在声明的同时初始化外,就只能在构
造方法中初始化。
(3 )final 修饰的方法不能被重置(在子类中不能出现同名方法)。
(4 )如果声明一个类为final ,则所有的方法均为final ,无论其是否被
final 修饰,但数据成员可为final 也可不是。
7 、接口interface (用implements来实现接口)
(1 )接口中的所有数据均为static和final 即静态常量。尽管可以不用这
两个关键字修饰,但必须给常量赋初值。
(2 )接口中的方法均为public,在实现接口类中,实现方法必须可public
关键字。
(3 )如果使用public来修饰接口,则接口必须与文件名相同。
8 、多重继承
(1 )一个类继承了一个类和接口,那么必须将类写在前面,接口写在后面,
接口之间用逗号分隔。
(2 )接口之间可多重继承,注意使用关键字extends.
(3 )一个类虽只实现了一个接口,但不仅要实现这个接口的所有方法,还
要实现这个接口继承的接口的方法,接口中的所有方法均须在类中实现。
9 、接口的嵌入
(1 )接口嵌入类中,可以使用private 修饰。此时,接口只能在所在的类
中实现,其他类不能访问。
(2 )嵌入接口中的接口一定要为public.
10、类的嵌入
(1 )类可以嵌入另一个类中,但不能嵌入接口中。
(2 )在静态方法或其他方法中,不能直接创建内部类tb对象,需通过手段来
取得。
手段有两种:
class A { class B {} B getB () { B b = new B(); return b ; }
} static void m () { A a = new A(); A.B ab = a.getB(); // 或者
是 A.B ab = a.new B (); }
(3 )一个类继承了另一个类的内部类,因为超类是内部类,而内部类的构
造方法不能自动被调用,这样就需要在子类的构造方法中明确的调用超类的构造
方法。接上例:
class C extends A.B { C () { new A()。super (); // 这一句就
实现了对内部类构造方法的调用。 } }
构造方法也可这样写:
C (A a ) { a.super(); } // 使用这个构造方法创建对象,要写成C
c = new C (a ); a是A 的对象。
11、异常类
JAVA中除了RunTimeException类,其他异常均须捕获或抛出。