其然IT教育集团是广州腾科网络技术有限公司旗下运营的网站平台。其然IT
教育集团是一家以提供新型、**的IT技术培训(教育)解决方案为主要经营目标的专业公司,是中国高端IT培训的**品牌。联合思科(Cisco)、甲
骨文(Oracle)、红帽(Red Hat)、华为(Huawei)、微软(Microsoft)、美国计算机行业协会(CompTIA)等国际知名IT厂商以 及国内300多家高等院校,
开展IT认证技能培训和IT职业课程教育,培养新型IT高级人才,是Pearson VUE国际电子考试中心和Prometric(普尔文)授权考试中心,并是达索
(solidworks)、安氏(LinkTrust)的授权经销商。
其然IT教育集团下辖上海分公司、深圳分公司、武汉分公司、杭州分公司等
8个分支机构。以及30多个培训网点,业务涵盖全国主要大、中型城市。
培训Java与自学Java的差距
我以前也是自学Java,在一家公司跟着别人学,以前是别人眼中的菜鸟,现
在是别人眼中的大神,Java很简单的,贵在坚持和多练,没必要花那培训钱。如果真的要去学的话,
选择Java培训机构要注意这两点基本上就能避免一些坑:
1. 老师没有正经公司工作经历,或者没有已经在线上正常运转的产品。一
些所谓培训班的老师水平往往比较一般,甚至还有培训出来后又接着培训别人的。
2、是不是会承诺帮你找到工作,要找到好的工作,不是靠别人给你保证的
,还是要靠自己提升能力。
建议多自己学习加上找些好的代码主动学习。例如github,多练习网上很多
网站里真正好的代码。作为Java工程师,可以多看看spring文档,看看很多已经成熟的框架,深入去体会。另外,学软件等等**好还是自己多学,找点
视频教程之类,也省点钱。
JavaWeb开发
-
01HTML5与CSS3
-
1.B/S架构
-
2.HTML基本使用
-
3.HTML DOM
-
4.CSS选择器
-
5.常用样式
-
6.盒子模型与布局
-
7.HTML5新特性
-
8.CSS3新特性
-
02JavaScript
-
1.JavaScript基本语法
-
2.JavaScript流程控制
-
3.数组、函数、对象的使用
-
4.JavaScript事件绑定/触发
-
5.JavaScript事件冒泡
-
6.JavaScript嵌入方式
-
7.JavaScript DOM操作
-
8.DOM API
-
03jQuery
-
1.jQuery快速入门
-
2.jQuery语法详解
-
3.jQuery核心函数
-
4.jQuery对象/JavaScript对象
-
5.jQuery选择器
-
6.jQuery 文档处理
-
7.jQuery事件
-
8.jQuery动画效果
-
04AJAX&JSON
-
1.AJAX技术衍生
-
2.XMLHttpRequest使用
-
3.同步请求&异步请求
-
4.JSON语法
-
5.Java JSON转换
-
6.JavaScript JSON转换
-
7.jQuery 基本AJAX方法
-
8.底层$.ajax使用
-
05XML
-
1.XML用途
-
2.XML文档结构
-
3.XML基本语法
-
4.DOM&SAX解析体系
-
5.DOM4j节点查询
-
6.DOM4j文档操作
-
7.xPath语法
-
8.xPath快速查询
-
06bootstrap
-
1.bootstrap快速使用
-
2.栅格系统
-
3.表单、表格、按钮、图片
-
4.下拉菜单
-
5.按钮组使用
-
6.导航条
-
7.分页、进度条
-
07Web服务器基础
-
1.HTTP协议
-
2.HttpWatch
-
3.Tomcat服务器搭建
-
4.Tomcat目录结构解析
-
5.Tomcat端口配置
-
6.Tomcat启动&停止
-
7.Tomcat&Eclipse整合
-
8.Eclipse配置优化
-
08Servlet
-
09JSP
-
1.JSP语法
-
2.JSP原理
-
3.JSP脚本片段&表达式
-
4.JSP声明&指令
-
5.JSP九大隐含对象
-
6.域对象使用
-
10JSTL
-
1.JSTL简介
-
2.JSTL-核心标签库
-
3.JSTL-函数标签库
-
4.JSTL-fmt标签库
-
5.自定义标签库使用
-
6.自定义标签库原理
-
11EL
-
1.EL表达式简介
-
2.EL使用
-
3.EL取值原理
-
4.EL的11大隐含对象
-
5.EL2.2与3.0规范
-
6.EL逻辑运算
-
7.函数库深入
-
12Cookie&Session
-
1.Cookie机制
-
2.Cookie创建&使用
-
3.Session原理
-
4.Session失效
-
5.Url重写
-
6.Session活化&钝化
-
7.Token令牌应用
-
13Filter&Listener
-
1.Filter原理
-
2.Filter声明周期
-
3.Filter链
-
4.Filter登录验证
-
5.Filter事务控制
-
6.Listener原理
-
7.八大监听器使用
-
8.Listener监听在线用户
-
14国际化
-
1.国际化原理
-
2.ResourceBundle&Locale
-
3.国际化资源文件
-
4.日期/数字/货币国际化
-
5.页面动态中英文切换
-
6.页面点击链接中英文切换
-
7.fmt标签库的使用
-
15文件上传
JAVA并发编程-线程间协作(Object监视器方法与Condition)
>
原文地址http://blog.csdn.net/zhshulin/article/details/50762465
说到线程间协作,不得不提到经典的生产者与消费者模型:有一个商品队列,生产者想队列中添加商品,消费者取出队列中的商品;显然,如果队列为空,消费者应该等待生产者产生商品才能消费;如果队列满了,生产者需要等待消费者消费之后才能生产商品。队列就是这个模型中的临界资源,当队列为空时,而消费者获得了该对象的锁,如果不释放,那么生产者无法获得对象锁,而消费者无法消费对象,就进入了死锁状态;反之队列满时,生产者不释放对象锁也会造成死锁。这是我们不希望看到的,所以就有了线程间协作来解决这个问题。
其实说到生产者与消费者模型,我们不能简单的知道怎么实现,而是需要知这种模型的使用场景:主要是为了复用和解耦,常见的消息框架(非常经典的一种生产者消费者模型的使用场景)ActiveMQ。发送端和接收端用Topic进行关联。
java语言中,如何实现线程间协作呢?比较常见的方法就是利用Object.wait(),Object.notify()和Condition。
先看看这几个方法究竟有什么作用?为什么利用它们就可以实现线程间协作了呢?
首先分析一下wait()/notify()/notifyAll()这三个Object监视器方法,比较早的方法,JDK1.5之前:
1、上述三个方法都是Object类中的本地方法,且为final,无法被重写;且这三个方法都必须在同步块或者同步方法中才能执行;
2、当前线程必须拥有该对象的锁,才能执行wait()方法,wait()方法会阻塞当前线程,并且释放对象锁;
3、notify()方法可以唤醒一个(1/N)正在等待这个资源锁的线程,但是不保证被唤醒的线程一定可以获得这个对象锁。
4、notifyAll()方法可以唤醒所有正在等待这个资源锁的线程,然后让它们去竞争资源锁,具体哪个能拿到就不知道了。
下面看如何使用上述的wait()和notify()方法来实现生产者与消费者模式:
[java] view
plain copy
PRint?
package org.zsl.learn.thread.join;
import java.util.PriorityQueue;
public class Producer implements Runnable{
private PriorityQueue<Integer> queue = null;
private int queueSize =0;
public Producer(PriorityQueue<Integer> queue,int queueSize){
this.queue=queue;
this.queueSize=queueSize;
}
public void product(){
while(true){
synchronized (queue) {
System.out.println("当前队列中数据数量是:" queue.size());
while(queue.size()==queueSize){//对于生产者来说需要判断的是队列是否满了,如果满了就等待
System.out.println("队列已满,等待消费者消费....");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify(); //这里为什么加个notify呢?是为了防止死锁,线程出现问题时,也要释放对象锁。
}
}
//如果队列没满,那么就往队列中加入数据
queue.offer(1);
queue.notify();
try {
Thread.sleep(100); //为什么加个休眠?是为了让我们可以在控制台看到生产者和消费者交替执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("向队列中插入一个数据,队列中剩余空间是:" (queueSize-queue.size()));
}
}
}
@Override
public void run() {
this.product();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join;
import java.util.PriorityQueue;
public class Consumer implements Runnable{
private PriorityQueue<Integer> queue = null;
public Consumer(PriorityQueue<Integer> queue){
this.queue=queue;
}
private void consume(){
while(true){
synchronized (queue) { //首先锁定对象
//如果队列为空,那么消费者无法消费,必须等待生产者产生商品,所以需要释放对象锁,并让自己进入等待状态
System.out.println("当前队列中剩余数据个数:" queue.size());
while(queue.size()==0) {
System.out.println("队列为空,等待数据......");
try {
queue.wait(); //使用wait()这个方法的时候,对象必须是获取锁的状态,调用了这个方法后,线程会释放该对象锁
} catch (InterruptedException e) {
e.printStackTrace();
queue.notify();//这里为什么加个notify呢?是为了防止死锁,线程出现问题时,也要释放对象锁。
}
}
//如果不为空,取出**个对象
queue.poll();
//注意notify()方法就是释放这个对象的锁,从而其他需要这个对象的线程中就会有一个能够获得锁,但是不能指定具体的线程
queue.notify();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("消费一个数据后,队列中剩余数据个数:" queue.size());
}
}
}
@Override
public void run() {
this.consume();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join;
import java.util.PriorityQueue;
public class Test {
public static void main(String[] args) {
int queueSize = 20;
//这里可以回忆一下JVM中多线程共享内存的知识
PriorityQueue<Integer> queue = new PriorityQueue<>(queueSize);
Consumer consumer = new Consumer(queue);
Producer producer = new Producer(queue, queueSize);
new Thread(consumer).start();
new Thread(producer).start();
}
}
-----------------------------------------------------------------------------------------------------
下面我们再来分析一下JAVA中的Condition又是什么呢?java.util.concurrent.locks.Condition是为了替代Object监视器方法。那么我们不经就要问:Condition相比较Object监视器的三个方法有什么差别呢?下面我们就来对比看看,到底差别在哪里?下面这个表展示了它们方法之间的共性。
|
Object
|
Condititon
|
休眠
|
wait
|
await
|
唤醒一个线程
|
notify
|
signal
|
唤醒所有线程
|
notifyAll
|
signalAll
|
使用Condition中,使用Lock来替代Synchronized关键字来实现操作的原子性,实现对临界资源的加锁与解锁,同样的,Condition中提供的三个方法也需要在“同步块”中进行。Condition相比较而言,强大的地方在于它能够精确的控制多线程的休眠与唤醒(注意是唤醒,唤醒并不表示该线程一定能够得到资源锁),这个意思就是有A/B/C/D四个线程共享Z资源,如果A占用了Z,并且调用了b_condition.notify()就可以释放资源唤醒B线程,而Object的nofity就无法保证B/C/D中会被唤醒哪一个了。其实多数线程间协作实用上述两种方式都可以实现,但是Sun推荐使用Condition来实现...我认为具体看你喜欢了,以及使用的熟练程度,除非你特别希望精确控制哪个线程被唤醒。
[java] view
plain copy
print?
package org.zsl.learn.thread.join2;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Producer2 implements Runnable{
private PriorityQueue<Integer> queue = null;
private int queueSize =0;
private Lock lock = null;
private Condition consume=null;
private Condition produce=null;
public Producer2(PriorityQueue<Integer> queue,int queueSize,Lock lock,Condition produce,Condition consume){
this.queue=queue;
this.queueSize=queueSize;
this.lock=lock;
this.consume=consume;
this.produce=produce;
}
public void product(){
while(true){
lock.lock();
try{
while(queue.size()==queueSize){
System.out.println("队列满了,等待消费者消费...");
try {
produce.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
consume.signal();
}
}
queue.offer(1);
System.out.println("向队列中插入了一个对象,队列的剩余空间是:" (queueSize-queue.size()));
consume.signal();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}finally{
lock.unlock();
}
}
}
@Override
public void run() {
this.product();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join2;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Consumer2 implements Runnable{
private PriorityQueue<Integer> queue = null;
private Lock lock = null;
private Condition consume=null;
private Condition produce=null;
public Consumer2(PriorityQueue<Integer> queue,Lock lock,Condition produce,Condition consume){
this.queue=queue;
this.lock =lock;
this.consume = consume;
this.produce = produce;
}
private void consume(){
while(true){
lock.lock();
try{
while(queue.size()==0){
System.out.println("队列为空,等待数据...");
try {
consume.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
produce.signal();
}
}
queue.poll();
System.out.println("从队列中取出一个元素,队列剩余数量是:" queue.size());
produce.signal();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}finally{
lock.unlock();
}
}
}
@Override
public void run() {
this.consume();
}
}
[java] view
plain copy
print?
package org.zsl.learn.thread.join2;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
public static void main(String[] args) {
int queueSize = 20;
PriorityQueue<Integer> queue = new PriorityQueue<>(queueSize);
Lock lock = new ReentrantLock();
Condition produce = lock.newCondition();
Condition consume = lock.newCondition();
Consumer2 consumer2 = new Consumer2(queue,lock,produce,consume);
Producer2 producer2 = new Producer2(queue, queueSize,lock,produce,consume);
new Thread(consumer2).start();
new Thread(producer2).start();
}
}
其实在上述两个代码的实现结果中,如果不加上Thread.sleep()来让线程睡眠,我们看到的结果就像是单线程一样,生产者填满队列,消费者清空队列。为什么会这样呢?我们注意到,在“同步块”中,如果不是队列的临界值(0、maxSize),仅仅是调用notify来唤醒一个等待该资源的线程,那么这个线程本身并没有进入等待状态,这个线程在释放这个锁之后会加入这个锁的竞争中,到底谁得到这个锁,其实也说不清楚,修改sleep的睡眠时间,可以看到从100毫秒到2000毫秒,设置不同的休眠时间,可以观察到生产者与消费者也不会出现交替进行,还是随机的。那么为什么要用Condition实现对确定线程的唤醒操作呢?唤醒了又不一定得到锁,这个需要使用到await()来让当前线程必须等到其他线程来唤醒才能控制生产者与消费者的交替执行。大家可以尝试一下:
在produce.signal()和consume.signal后面分别加上:consume.await()和produce.await即可实现生产者和消费者(多个线程也可以控制任意两个线程交替执行)的交替执行,这个呢,使用Object监视器方法在多个线程的情况下是不可能实现的,但是仅仅2个线程还是可以的。上述列子中,如果有多个消费者,那么如何在生产者完成生产后就只唤醒消费者线程呢?同样,用Condition实现就非常简单了,如果使用Object监视器类也可以实现,大家不妨想一下,但是相对复杂,编程过程中容易出现死锁。
相关推荐:
苏州JAVA培训 苏州JAVA培训班 苏州JAVA培训机构