第一篇:java培训-Java高并发(大全)
Java高并发:静态页面生成方案
提升网站性能的方式有很多,例如有效的使用缓存,生成静态页面等等。今天要说的就是生成静态页面的方式。这个也是我近期一直在搞的一个问题,近期在做使用html + servlet做个人网站,为什么是这2个东西呢?
提升网站性能的方式有很多,例如有效的使用缓存,生成静态页面等等。今天要说的就是生成静态页面的方式。这个也是我近期一直在搞的一个问题,近期在做使用html + servlet做个人网站,为什么是这2个东西呢?
1、直接用servlet是为了保证网站能以最快的速度执行命令..个人总感觉像Struts hibernate spring之类的虽然方便但是效能带来的损耗不太能接收
2、使用html同样是为了保证最快的反应速度,毕竟html 比jsp少了一层服务器执行.速度上要快的多
一、在这里要先说一下什么是页面静态化:
简单的说,我们如果访问一个链接 http://abc.com/test.do,服务器对应的模块会处理这个请求,转到对应的jsp界面,最后生成我们想要看到的数据。这其中的缺点是显而易见的:因为每次请求服务器都会进行处理,如果有太多的高并发请求,那么就会加重应用服务器的压力,弄不好就把服务器 搞down 掉了。那么如何去避免呢?如果我们把对 test.do 请求后的结果保存成一个 html 文件,然后每次用户都去访问 http://abc.com/test.html,这样应用服务器的压力不就减少了?
那么静态页面从哪里来呢?总不能让我们每个页面都手动处理吧?这里就牵涉到我们要讲解的内容了,静态页面生成方案...我们需要的是自动的生成静态页面,当用户访问 http://abc.com/test.do,会自动生成 test.html,然后显示给用户。
二、下面我们在简单介绍一下要想掌握页面静态化方案应该掌握的知识点
1、基础— URL Rewrite 什么是 URL Rewrite 呢 ? URL 重写。用一个简单的例子来说明问题:输入网址http://www.xiexiebang.com/test.do,但是实际上访问的却是 http://www.xiexiebang.com/test.action,那我们就可以说 URL 被重写了。这项技术应用广泛,有许多开源的工具可以实现这个功能。
2、基础— Servlet web.xml 如果你还不知道 web.xml 中一个请求和一个 servlet 是如何匹配到一起的,那么请搜索一下 servlet 的文档。这可不是乱说呀,有很多人就认为 /xyz/*.do 这样的匹配方式能有效。
如果你还不知道怎么编写一个 servlet,那么请搜索一下如何编写 servlet。这可不是说笑呀,在各种集成工具漫天飞舞的今天,很多人都不会去从零编写一个 servlet了。
三、基本的方案介绍
其中,对于 URL Rewriter的部分,可以使用收费或者开源的工具来实现,如果 url不是特别的复杂,可以考虑在 servlet 中实现,那么就是下面这个样子:
原文链接:中软卓越http://www.xiexiebang.com
第二篇:Java培训
广州传智播客Java培训的优势在哪里?
众所周知,传智播客广州Java培训课程在业界可算是是一流的。计算机技术的发展日新月异,为紧跟技术潮流,广州传智播客多名资深Java专家,在多个预热班的实践基础上,综合课堂反馈,结合现今流行的多种实用技术,在原有课程再次加入了多个实用性、趣味性很强的Java项目:网络蚂蚁,网络爬虫,聊天系统。
传智播客广州Java培训课程可谓是全国最牛的。由于受全球金融危机的影响,IT行业萎缩、人才需求下滑,现在的情况是:一个工作岗位往往几佰人竞争,队伍中更是不缺乏具有一、二年工作经验的开发人员。如何让自己在几佰人的竞争中脱颖而出?没有他途,只有把技术学的更深入,更牛,方能取胜。在广州传智播客学习Java课程不但可以让你找到工作,更能让你找到一份好工作。
心动不如行动,赶快来广州传智播客Java培训机构学习吧!这里将会是你一个展示你技术价值的好平台!
第三篇:关于Java并发编程的总结和思考
关于Java并发编程的总结和思考
编写优质的并发代码是一件难度极高的事情。Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的,但是当我们对并发编程有了更深刻的认识和更多的实践后,实现并发编程就有了更多的方案和更好的选择。本文是对并发编程的一点总结和思考,同时也分享了Java 5以后的版本中如何编写并发代码的一点点经验。
为什么需要并发
并发其实是一种解耦合的策略,它帮助我们把做什么(目标)和什么时候做(时机)分开。这样做可以明显改进应用程序的吞吐量(获得更多的CPU调度时间)和结构(程序有多个部分在协同工作)。做过Java Web开发的人都知道,Java Web中的Servlet程序在Servlet容器的支持下采用单实例多线程的工作模式,Servlet容器为你处理了并发问题。
误解和正解
最常见的对并发编程的误解有以下这些:
-并发总能改进性能(并发在CPU有很多空闲时间时能明显改进程序的性能,但当线程数量较多的时候,线程间频繁的调度切换反而会让系统的性能下降)
-编写并发程序无需修改原有的设计(目的与时机的解耦往往会对系统结构产生巨大的影响)
-在使用Web或EJB容器时不用关注并发问题(只有了解了容器在做什么,才能更好的使用容器)
下面的这些说法才是对并发客观的认识:
-编写并发程序会在代码上增加额外的开销
-正确的并发是非常复杂的,即使对于很简单的问题
-并发中的缺陷因为不易重现也不容易被发现
-并发往往需要对设计策略从根本上进行修改 并发编程的原则和技巧
单一职责原则
分离并发相关代码和其他代码(并发相关代码有自己的开发、修改和调优生命周期)。限制数据作用域
两个线程修改共享对象的同一字段时可能会相互干扰,导致不可预期的行为,解决方案之一是构造临界区,但是必须限制临界区的数量。使用数据副本
数据副本是避免共享数据的好方法,复制出来的对象只是以只读的方式对待。Java 5的java.util.concurrent包中增加一个名为CopyOnWriteArrayList的类,它是List接口的子类型,所以你可以认为它是ArrayList的线程安全的版本,它使用了写时复制的方式创建数据副本进行操作来避免对共享数据并发访问而引发的问题。线程应尽可能独立
让线程存在于自己的世界中,不与其他线程共享数据。有过Java Web开发经验的人都知道,Servlet就是以单实例多线程的方式工作,和每个请求相关的数据都是通过Servlet子类的service方法(或者是doGet或doPost方法)的参数传入的。只要Servlet中的代码只使用局部变量,Servlet就不会导致同步问题。springMVC的控制器也是这么做的,从请求中获得的对象都是以方法的参数传入而不是作为类的成员,很明显Struts 2的做法就正好相反,因此Struts 2中作为控制器的Action类都是每个请求对应一个实例。Java 5以前的并发编程
Java的线程模型建立在抢占式线程调度的基础上,也就是说:
所有线程可以很容易的共享同一进程中的对象。能够引用这些对象的任何线程都可以修改这些对象。为了保护数据,对象可以被锁住。
Java基于线程和锁的并发过于底层,而且使用锁很多时候都是很万恶的,因为它相当于让所有的并发都变成了排队等待。
在Java 5以前,可以用synchronized关键字来实现锁的功能,它可以用在代码块和方法上,表示在执行整个代码块或方法之前线程必须取得合适的锁。对于类的非静态方法(成员方法)而言,这意味这要取得对象实例的锁,对于类的静态方法(类方法)而言,要取得类的Class对象的锁,对于同步代码块,程序员可以指定要取得的是那个对象的锁。
不管是同步代码块还是同步方法,每次只有一个线程可以进入,如果其他线程试图进入(不管是同一同步块还是不同的同步块),JVM会将它们挂起(放入到等锁池中)。这种结构在并发理论中称为临界区(critical section)。这里我们可以对Java中用synchronized实现同步和锁的功能做一个总结:
只能锁定对象,不能锁定基本数据类型 被锁定的对象数组中的单个对象不会被锁定
同步方法可以视为包含整个方法的synchronized(this){ „ }代码块 静态同步方法会锁定它的Class对象 内部类的同步是独立于外部类的
synchronized修饰符并不是方法签名的组成部分,所以不能出现在接口的方法声明中 非同步的方法不关心锁的状态,它们在同步方法运行时仍然可以得以运行 synchronized实现的锁是可重入的锁。
在JVM内部,为了提高效率,同时运行的每个线程都会有它正在处理的数据的缓存副本,当我们使用synchronzied进行同步的时候,真正被同步的是在不同线程中表示被锁定对象的内存块(副本数据会保持和主内存的同步,现在知道为什么要用同步这个词汇了吧),简单的说就是在同步块或同步方法执行完后,对被锁定的对象做的任何修改要在释放锁之前写回到主内存中;在进入同步块得到锁之后,被锁定对象的数据是从主内存中读出来的,持有锁的线程的数据副本一定和主内存中的数据视图是同步的。
在Java最初的版本中,就有一个叫volatile的关键字,它是一种简单的同步的处理机制,因为被volatile修饰的变量遵循以下规则:
变量的值在使用之前总会从主内存中再读取出来。对变量值的修改总会在完成之后写回到主内存中。
使用volatile关键字可以在多线程环境下预防编译器不正确的优化假设(编译器可能会将在一个线程中值不会发生改变的变量优化成常量),但只有修改时不依赖当前状态(读取时的值)的变量才应该声明为volatile变量。
不变模式也是并发编程时可以考虑的一种设计。让对象的状态是不变的,如果希望修改对象的状态,就会创建对象的副本并将改变写入副本而不改变原来的对象,这样就不会出现状态不一致的情况,因此不变对象是线程安全的。Java中我们使用频率极高的String类就采用了这样的设计。如果对不变模式不熟悉,可以阅读阎宏博士的《Java与模式》一书的第34章。说到这里你可能也体会到final关键字的重要意义了。
Java 5的并发编程
不管今后的Java向着何种方向发展或者灭忙,Java 5绝对是Java发展史中一个极其重要的版本,这个版本提供的各种语言特性我们不在这里讨论(有兴趣的可以阅读我的另一篇文章《Java的第20年:从Java版本演进看编程技术的发展》),但是我们必须要感谢Doug Lea在Java 5中提供了他里程碑式的杰作java.util.concurrent包,它的出现让Java的并发编程有了更多的选择和更好的工作方式。Doug Lea的杰作主要包括以下内容:
更好的线程安全的容器 线程池和相关的工具类 可选的非阻塞解决方案 显示的锁和信号量机制
下面我们对这些东西进行一一解读。
原子类
Java 5中的java.util.concurrent包下面有一个atomic子包,其中有几个以Atomic打头的类,例如AtomicInteger和AtomicLong。它们利用了现代处理器的特性,可以用非阻塞的方式完成原子操作,代码如下所示: /** ID序列生成器 */ public class IdGenerator {
private final AtomicLong sequenceNumber = new AtomicLong(0);
public long next(){
return sequenceNumber.getAndIncrement();
} } 显示锁
基于synchronized关键字的锁机制有以下问题:
锁只有一种类型,而且对所有同步操作都是一样的作用 锁只能在代码块或方法开始的地方获得,在结束的地方释放 线程要么得到锁,要么阻塞,没有其他的可能性
Java 5对锁机制进行了重构,提供了显示的锁,这样可以在以下几个方面提升锁机制:
可以添加不同类型的锁,例如读取锁和写入锁 可以在一个方法中加锁,在另一个方法中解锁
可以使用tryLock方式尝试获得锁,如果得不到锁可以等待、回退或者干点别的事情,当然也可以在超时之后放弃操作 显示的锁都实现了java.util.concurrent.Lock接口,主要有两个实现类:
ReentrantLock在读操作很多写操作很少时性能更好的一种重入锁
对于如何使用显示锁,可以参考我的Java面试系列文章《Java面试题集51-70》中第60题的代码。只有一点需要提醒,解锁的方法unlock的调用最好能够在finally块中,因为这里是释放外部资源最好的地方,当然也是释放锁的最佳位置,因为不管正常异常可能都要释放掉锁来给其他线程以运行的机会。
CountDownLatch
CountDownLatch是一种简单的同步模式,它让一个线程可以等待一个或多个线程完成它们的工作从而避免对临界资源并发访问所引发的各种问题。下面借用别人的一段代码(我对它做了一些重构)来演示CountDownLatch是如何工作的。
import java.util.concurrent.CountDownLatch;/** * 工人类
* @author 骆昊
* */ class Worker {
private String name;
// 名字
private long workDuration;// 工作持续时间
/**
* 构造器
*/
public Worker(String name, long workDuration){
this.name = name;
this.workDuration = workDuration;
}
/**
* 完成工作
*/
public void doWork(){
System.out.println(name + “ begins to work...”);
try {
Thread.sleep(workDuration);// 用休眠模拟工作执行的时间
} catch(InterruptedException ex){
ex.printStackTrace();
}
System.out.println(name + “ has finished the job...”);
} } /** * 测试线程
* @author 骆昊
* */ class WorkerTestThread implements Runnable {
private Worker worker;
private CountDownLatch cdLatch;
public WorkerTestThread(Worker worker, CountDownLatch cdLatch){
this.worker = worker;
this.cdLatch = cdLatch;
}
@Override
public void run(){
worker.doWork();
// 让工人开始工作
cdLatch.countDown();
// 工作完成后倒计时次数减1
} } class CountDownLatchTest {
private static final int MAX_WORK_DURATION = 5000;// 最大工作时间
private static final int MIN_WORK_DURATION = 1000;// 最小工作时间
// 产生随机的工作时间
private static long getRandomWorkDuration(long min, long max){
return(long)(Math.random()*(max1);// 如果有N个哲学家,最多只允许N-1人同时取叉子
}
/**
* 取得叉子
* @param index 第几个哲学家
* @param leftFirst 是否先取得左边的叉子
* @throws InterruptedException
*/
public static void putOnFork(int index, boolean leftFirst)throws InterruptedException {
if(leftFirst){
forks[index].acquire();
forks[(index + 1)% NUM_OF_PHILO].acquire();
}
else {
forks[(index + 1)% NUM_OF_PHILO].acquire();
forks[index].acquire();
}
}
/**
* 放回叉子
* @param index 第几个哲学家
* @param leftFirst 是否先放回左边的叉子
* @throws InterruptedException
*/
public static void putDownFork(int index, boolean leftFirst)throws InterruptedException {
if(leftFirst){
forks[index].release();
forks[(index + 1)% NUM_OF_PHILO].release();
}
else {
forks[(index + 1)% NUM_OF_PHILO].release();
forks[index].release();
}
} } /** * 哲学家
* @author 骆昊
* */ class Philosopher implements Runnable {
private int index;
// 编号
private String name;
// 名字
public Philosopher(int index, String name){
this.index = index;
this.name = name;
}
@Override
public void run(){
while(true){
try {
AppContext.counter.acquire();
boolean leftFirst = index % 2 == 0;
AppContext.putOnFork(index, leftFirst);
System.out.println(name + “正在吃意大利面(通心粉)...”);
// 取到两个叉子就可以进食
AppContext.putDownFork(index, leftFirst);
AppContext.counter.release();
} catch(InterruptedException e){
e.printStackTrace();
}
}
} }
public class Test04 {
public static void main(String[] args){
String[] names = { “骆昊”, “王大锤”, “张三丰”, “杨过”, “李莫愁” };
// 5位哲学家的名字
//
ExecutorService es = Executors.newFixedThreadPool(AppContext.NUM_OF_PHILO);// 创建固定大小的线程池 //
for(int i = 0, len = nawww.xiexiebang.commes.length;i < len;++i){ //
es.execute(new Philosopher(i, names[i]));
// 启动线程 //
} //
es.shutdown();
for(int i = 0, len = names.length;i < len;++i){
new Thread(new Philosopher(i, names[i])).start();
}
} }
现实中的并发问题基本上都是这三种模型或者是这三种模型的变体。
测试并发代码
对并发代码的测试也是非常棘手的事情,棘手到无需说明大家也很清楚的程度,所以这里我们只是探讨一下如何解决这个棘手的问题。我们建议大家编写一些能够发现问题的测试并经常性的在不同的配置和不同的负载下运行这些测试。不要忽略掉任何一次失败的测试,线程代码中的缺陷可能在上万次测试中仅仅出现一次。具体来说有这么几个注意事项:
不要将系统的失效归结于偶发事件,就像拉不出屎的时候不能怪地球没有引力。先让非并发代码工作起来,不要试图同时找到并发和非并发代码中的缺陷。编写可以在不同配置环境下运行的线程代码。
编写容易调整的线程代码,这样可以调整线程使性能达到最优。
让线程的数量多于CPU或CPU核心的数量,这样CPU调度切换过程中潜在的问题才会暴露出来。让并发代码在不同的平台上运行。
通过自动化或者硬编码的方式向并发代码中加入一些辅助测试的代码。Java 7的并发编程
Java 7中引入了TransferQueue,它比BlockingQueue多了一个叫transfer的方法,如果接收线程处于等待状态,该操作可以马上将任务交给它,否则就会阻塞直至取走该任务的线程出现。可以用TransferQueue代替BlockingQueue,因为它可以获得更好的性能。
刚才忘记了一件事情,Java 5中还引入了Callable接口、Future接口和FutureTask接口,通过他们也可以构建并发应用程序,代码如下所示。
import java.util.ArrayList;import java.util.List;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;
public class Test07 {
private static final int POOL_SIZE = 10;
static class CalcThread implements Callable
private List
public CalcThread(){
for(int i = 0;i < 10000;++i){
dataList.add(Math.random());
}
}
@Override
public Double call()throws Exception {
double total = 0;
for(Double d : dataList){
total += d;
}
return total / dataList.size();
}
}
public static void main(String[] args){
List
ExecutorService es = Executors.newFixedThreadPool(POOL_SIZE);
for(int i = 0;i < POOLwww.xiexiebang.compute(){
int sum = 0;
if((end-start)< THRESHOLD){
// 当问题分解到可求解程度时直接计算结果
for(int i = start;i <= end;i++){
sum += i;
}
} else {
int middle =(start + end)>>> 1;
// 将任务一分为二
Calculator left = new Calculator(start, middle);
Calculator right = new Calculator(middle + 1, end);
left.fork();
right.fork();
// 注意:由于此处是递归式的任务分解,也就意味着接下来会二分为四,四分为八...sum = left.join()+ right.join();
// 合并两个子任务的结果
}
return sum;
} }
public class Test08 {
public static void main(String[] args)throws Exception {
ForkJoinPool forkJoinPool = new ForkJoinPool();
Future
System.out.println(result.get());
} }
伴随着Java 7的到来,Java中默认的数组排序算法已经不再是经典的快速排序(双枢轴快速排序)了,新的排序算法叫TimSort,它是归并排序和插入排序的混合体,TimSort可以通过分支合并框架充分利用现代处理器的多核特性,从而获得更好的性能(更短的排序时间)。
第四篇:java实战培训
Java实战培训
Java作为全世界使用最广泛的编程语言,java程序员也是全球最受欢迎的职业之一。java的跨平台性受到了许多权威机构的肯定,java语言更是在it行业倍受企业的青睐。尚学堂java培训实战课程。1-4阶段6个真实项目,带你一步步揭秘java项目实战编程。让你从一个菜鸟编程一个编程高手。【培训项目】
大学生java实战班,大学生java就业班 【项目案例】
第一阶段项目:
CHAT项目 Chat项目通过完成一个模拟的在线聊天系统,主要锻炼大家对于TCP/IP、Socket编程、C/S模式的编程、线程的运用等方面的能力。
坦克大战单机版/图片版/网络版 这三个项目通过大家喜闻乐见的小游戏的形式来锻炼大家对于JavaSE综合运用的能力,并且能够初步运用面向对象的编程理念,锻炼初步的设计能力,并基本掌握多线程的编程。
第二阶段项目:
BBS的两个项目完成了一个具备完善前台展现以及后台管理的论坛系统,论坛系统的业务逻辑大家比较熟悉,是用来进行JavaWeb开发的极好的入门系统。但是由于其业务逻辑太简单,尚学堂目前的课程体系中已经用搜索项目来替代它。
第三阶段项目:
BBS项目:Credit Control System属银行核心业务系统的主要子系统之一,在这个项目中,同学们将锻炼自己的EJB3.0的知识,同时了解金融方面的知识,做到技术+业务的双重深入,为以后进入金融行业铺平道路。
CCS项目:Credit Control System属银行核心业务系统的主要子系统之一,在这个项目中,同学们将锻炼自己的EJB3.0的知识,同时了解金融方面的知识,做到技术+业务的双重深入,为以后进入金融行业铺平道路。
第四阶段android项目:
楼层日常信息监控系统:本系统是专为大型楼盘与机构等开发的楼层日常信息监控系统,管理人员可以查看室内温度,室内湿度,UPS,电压,空调运行情况等,还可以执行空调漏水和电压报警。本软件功能:查看室内温度,室内湿度,UPS,电压,空调运行情况,空调漏水报警,烟雾探测器等,室内温度和湿度以及电压设置报警。本软件除硬件设备包括服务器的opc探测及传输,基础价为30万,如需其他功能,价格面议,欲购此软件的企业请与西安尚学堂联系。
Android平板电脑移动OA:该软件可以实现在Android系统的平板电脑上进行客户管理、日程管理、文件审批、企业通讯录、邮箱、论坛等功能。
【培训对象】
1、大专以上学历,在校大学生或者在职人群;
2、有良好的计算机基础,能阅读简单的英文文档;
3、有志于从事IT行业。
学校名称:西安雁塔尚学堂计算机学校 学校网址:www.xiexiebang.com
报名热线:029-82300161
第五篇:Java培训感言
甲骨文盈佳科技Java培训感言
为什么要学Java? 首要的原因当然是为了生活,找份好工作。入门学习过程是比较痛苦的,要学好需要一定的努力,但是有一个好处,相对Java来说比较集中,不会出现Java里面这么多差异。Java的学习过程开始比较容易入手,更容易学习。
Java还有一个优势就是在移动设备的开发,所有的Java应用版本不同,但是语法一致。Java的跨平台特性可以让我们在不同的场合下使用。开始的两年我学Java就是拿书看,练习书上的例子,但是一直没有好的效果,后来就去甲骨文盈佳科技原厂Java培训机构进行系统的学习了,毕竟比自学要轻松些,另外还可以学到别人的一些经验。
学习的过程中不可避免的遇到问题,这些问题有的只是一个符号错了,一个括号少了,这类的问题在文档里,或者一般的网站上就能够找到,尤其是初学者的问题,不会是很难的问题,之前已经有无数人问过了,不要害怕提问,但是这个问题最好是你找不到答案的时候去提。编程是一种乐趣,只有你觉得他有乐趣的时候你才会用更多的热情去学习,及时总结昨天、做好今天、规划好明天
感谢甲骨文盈佳科技所有的老师对我的帮助,也祝甲骨文盈佳科技越办越好