- 浏览: 153904 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
lanhaitun1991:
亲,其实你这里介绍的方法有一个最大的问题:如果放入队列之后,但 ...
分布式事务 -
lp385267935:
不错 很好用~3Q
jsonlib json-->object,忽略object中没有的属性 -
xiebo1983:
http://www.sqkoo.com/show/detai ...
mysql latin1乱码 -
envy2002:
当然可以了,tomcat中源码你可以看看,只要“欺骗”过去to ...
tomcat中的长连接 -
newSaa:
问一下,可以在 tomcat 建立tcp 长连接吗?
tomcat中的长连接
线程间的通信
如果线程只是傻傻地一个劲的“排他的”前行,那必然是愚蠢的。线程间需要通信,他们需协作才完成某项任务。线程间通常都是各顾各地前行,当然他们有公共资源的时候,需要调成按一定秩序执行。打个比方:福特汽车的流水线,for example,有一个流程是这样的:做好底盘的工人把底盘放在传送带上,传给上轮胎的工人。两个部分的工人只是埋头苦干,大部分时间不需要协调。如果做底盘的工人速度慢了,那么上轮胎的工人就闲着了,要等。如果上轮胎的工人很慢,做底盘的可以喝口水,抽口烟了,呵呵。这和线程很像:只关心自己的事情,但是在"边缘"的地方,双方需要协调。这就需要线程能有"停止"和"再启动"的能力。对应的方法是:wait(),notify();其中wait()是释放锁资源。 锁资源相当于CPU的时间片资源,需要注意的是它只能用在synchronized(锁)起来的程序片段中,不可以乱放。notify是通知那些在等的线程,然后在这些等的线程中,产生一个幸运儿,占有这个锁。许多书说notifyAll()好,我们就直接用notifyAll得了,反正功能差不多,偶也说不清,就不说了,呵呵。还有一点,wait能释放锁资源,sleep可不行哦,面试经常要问的哦。
我们还是举例子来说吧:经典的生产者和消费者:
原始问题描述:有一个大篮子,姑娘不停地在玉米地摘玉米棒子,丢进大篮子里面。小伙子不停地从篮子里面拿玉米,扔到火锅里煮。
问题升级1.姑娘不止一个,小伙子也不止一个。
问题升级2.说不定有n个大妈从火锅里里面捞玉米,准备包装上市。
如果用顺序编程的想法考虑问题就是:玉米被姑娘摘下,放到篮子里面,玉米被小伙拿出篮子,玉米被小伙放进锅里面,玉米被大娘拿出,包装。呵呵,很冗长,不是吗?
如果一开始篮子里面就有100个棒子,姑娘累了,想歇歇腰,小伙子照样有活干。小伙子想上茅房,大篮子还很空,姑娘 照样可以一个人单干。这是另一种劳动模式了,极大地解放了社会主义的生产力,值得提倡,呵呵。
那么,我们考虑原始问题的解答:
第一步考虑到是公共资源,是什么呢?篮子。
第二步"临界点":篮子满了,姑娘不能放玉米了,要等小伙子;小伙子不能从空篮子里面拿玉米,小伙子要等。
小伙子如果从满篮子里面拿了一个玉米,要通知姑娘,你该干活了。同理,姑娘从空篮子里面放一个玉米要通知小伙 开工。
第三步:并发问题的真正瓶颈,搞清楚,哪里该并发,哪里不该。
问题如图示:
伪代码: vector //模拟篮子 对小伙子来说: public synchronized YuMi getYuMi() { YuMi yumi=new Yumi(); if(vector.size()==0) { wait(); //等待完毕,请立刻取玉米,不妨取最后一个。 yumi=vector.last(); } //如果篮子不为空,尽情取 else { yumi=vector.last(); //如果是从满篮子中取的,please notify姑娘 if(vector.size==vector.MAX-1) notifyAll(); } }
同理,也能很快得到姑娘放玉米的逻辑:省略
注意:也有人喜欢这样写,用while做判断,这样是简洁许多,但是逻辑不够清晰:
public synchronized YuMi getYuMi() { YuMi yumi=new Yumi(); while(vector.size()==0) { wait(); //等待完毕,请立刻取玉米,不妨取最后一个。 } //如果篮子不为空,尽情取 yumi=vector.last(); //如果是从满篮子中取的,please notify姑娘 if(vector.size==vector.MAX-1) notifyAll(); }
生产者和消费者模型的代码如下:
公共资源类:
package producer_and_consumer; import java.util.Vector; public class Basket { private Vector vector=new Vector(); private int Max=20; public synchronized String getYuMi() { String yumi=new String(); while(vector.size()==0) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } yumi=(String) vector.elementAt(vector.size()-1); vector.remove(vector.size()-1); System.out.println(Thread.currentThread()+" "+"Get "+ yumi); if(vector.size()==(Max-1)) notifyAll(); return yumi; } public synchronized void putYuMi(String str) { System.out.println(Thread.currentThread()+" "+"Put "+ str); while(vector.size()==Max) { try { wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } vector.add(vector.size(),str); if(vector.size()==1) notifyAll(); } }
生产者线程:
package producer_and_consumer; public class Producer extends Thread{ private Basket basket; private String prefix="YuMi"; private String yumi; private int i=0; public Producer(Basket basket) { this.basket=basket; } public void run() { for(int j=0;j<100;j++) { i++; yumi=prefix+i; try { Thread.sleep((int) ((long)1000* Math.random())); //为了模拟生产者隔一段时间生产一个,同理也可以在消费线程中 //加上这个随机模拟,可以观察输出。 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } basket.putYuMi(yumi); } } }
消费者线程:
package producer_and_consumer; public class Consumer extends Thread{ private Basket basket; public Consumer(Basket basket) { this.basket=basket; } public void run() { while(true) { basket.getYuMi(); } } }
程序入口:
package producer_and_consumer; public class main { public static void main(String args[]) { Basket ball= new Basket(); Thread producer=new Producer(ball); Thread consumer=new Consumer(ball); producer.start(); consumer.start(); } }
输入在自己机器上看,因为太随机了!
在继续下面的时候,我们得讨论一下锁的对象和锁的大小即锁的粒度。
class Object1 { private Object2 obj2; public Object3 obj3=new Object3(); public synchronize void function1() { } public void function2() { synchronized(obj3) { } } }
对象Object1中包含了对象Object2和Object3,function1()加锁的粒度是object1,
function2()加锁的粒度是obj3,可以说,obj3要小一些。当然,不意味着obj1加锁,就
给obj2,obj3加了锁,虽然类的组织是个包含关系,可是,锁是加在对象或者类上的,(加在类上的
是静态方法,这里不予讨论,因为我自己都没研究过,呵呵。)
为什么要这样分呢,我们下面讨论。
从上面的那个生产者消费者可以看出锁是加在整个vector上的,所以put和get方法,一次只能进一个。所以
有同志觉得这不行,效率不高.如果我们现在考虑现在有n个生产者,n个消费者,我们希望把锁的粒度降低为
vector中的一个个节点,各个结点颜色不同,不是可以并发,效率更好了吗?猛然一想,这样觉得确实挺酷。
但是我觉得很难:线程都是埋头苦干型的,他最得意的时候就是不停地做,而不要关心其他线程在干什么,但是
有时候不得不考虑:我们假设有一个容器,放东西的线程在放的时候,需要不需要考虑其他线程。当然需要,我们
定位的时候,当然需要知道哪些位置是放过东西的,那些是没放过的,这是有先后因果关系的,所以这些线程必须是顺 序执行!,必须一个一个进,不能同时涌进来。当然,这是我个人看法,因为我没有找到,让多个让多个物体并发放入容器的方法。证明过程如下: 如果一个线程要把东西塞进容器,它需要知道容器的size,容器知道size,需要检索每一个节点,每一个精确的检索,不能让其他线程破坏,所以证明没有同时多个线程往容器中放东西的方法。当然也不是不可能,呵呵,如果换了一种数据结构,或者用hash技术,或者其他好的数据结构,希望有人能告诉我,呵呵。 至于图9提出的想法,只能多个1对1的生产者消费者模型的n倍翻版,因为任何一个节点满了,都会导致放的线程 停止,而不会让他自己去寻找其他的空白节点,呵呵。所以我们要讨论一下,我们要在何时并发,哪里能并发。
真正的瓶颈在哪里?
还是拿上面姑娘摘玉米,小伙子煮玉米,大娘搞包装来说,姑娘们把玉米放在篮子很简单,小伙子从篮子拿出玉米也简单,呵呵,同理从火锅里拿放玉米也简单,正在花费时间的是姑娘摘玉米,小伙子剥玉米皮,洗玉米,大娘搞包装袋 这些花费的时间是拿、取的好几个数量级,不是吗,这些人可以并发吗?当然,一个小伙子拿起一个自己的玉米,我想,他自己干自己的,就行了,根本就不要和其他小伙子协作。所以这里是真正要并发的地方。
还有最后一个加强问题,如果大妈后面还有许多人,那怎么搞?一直用线程吗?我的建议是没必要搞那么多线程,可以把一些步骤合成一个顺序执行,只在关键点,搞成并发的线程。不要为了多线程而线程。
所以,有了多线程,我们考虑问题的模式就变了:如果你一上来,就把一个"实体"的方法写一个synchronizd, 然后口口声声地说,这个是线程安全的。你一定是绵羊座,O型血的人,您的世界观一定很狭窄。真的猛士是不惧怕并发的。 我们应该以一种完全并发的角度来考虑问题,因为并发太可爱了,他高效,直白。然后再考虑竞争条件,哪里不能并发,并发有没有意义。其中竞争条件是公共资源,并发的意义是搞清楚真正耗时的步骤。就像我一开始就没搞清楚,从数据库load数据到内存是个查询的瓶颈一样,所以搞清真正的瓶颈很关键。
发表评论
-
java NIO
2013-05-02 16:51 791... -
Thread.interrupt
2013-04-10 21:25 1015Thread.interrupt(),就是置状态。 ... -
分布式事务2
2013-02-19 14:16 10231.jar包,应该用带有二步提交事务的驱动,mysq ... -
分布式事务
2013-02-17 17:40 2405... -
spring SimpleFormController流程
2013-02-08 11:43 1782最近在学习spring mvc. 网上了收集了一下Simp ... -
ASM 使用的一个范例。
2012-10-19 14:05 4591现在开始研究Junit,试图通过Junit来改善自己的编 ... -
谷歌面试题一枚
2012-10-16 09:46 1293机械开发代码久了,看了看一些面试题,可以活跃大脑,最近网上看了 ... -
java concurrent学习记录
2012-10-10 09:51 937今天决定学习一下java.concurrent包,以这个 ... -
jsonlib json-->object,忽略object中没有的属性
2012-09-21 09:42 10010Java code skel ... -
java并发编程pdf纠错
2012-08-14 09:21 0java并发编程实践里面讲究CAS算法,其中这个 算法comp ... -
5分钟内搞定 Tomcat 的 SSL 配置
2012-07-02 11:52 9035分钟内搞定 Tomcat 的 SSL 配置(转) ... -
java nio测试
2012-06-29 12:00 995import java.io.IOException; ... -
屌丝comet
2012-06-26 09:29 872很显然tomcat能和浏览器之间实现长连接还是不错的,看了ib ... -
eclipse 远程调试 web程序
2012-05-31 16:37 992需要远程调试web程序,没办法啊。 1. 需要把%TO ... -
tomcat停止
2012-04-18 12:50 0#!/bin/sh #kill tomcat pid ... -
json转java对象
2012-04-10 20:54 1057String json = "{\&qu ... -
bonecp源码陌生类选读
2012-03-01 17:16 837今天在学习bonecp源码,看到了好多从来没有用过的类,现在记 ... -
TOMCAT源码分析(消息处理)(转)
2012-02-28 14:06 788TOMCAT源码分析(消息处理) http://bl ... -
tomcat流程启动图
2012-02-28 10:56 971tomcat6从启动到监听8080端口来处理请求的过程,如图: ... -
tomcat源码的几个问题
2012-02-24 11:31 9631. tomcat如何区分静态页面.html .jpg 和.j ...
相关推荐
Java多线程是Java编程中的一个核心概念,它在现代软件开发中扮演着至关重要的角色。...通过深入学习和实践上述Java多线程的知识点,开发者能够构建出高效、稳定、可控的多线程程序,满足各种复杂的并发需求。
### Java中的多线程学习总结 #### 一、线程与进程的概念 在计算机科学中,**进程**和**线程**是两个重要的概念。早期的Windows 3.x系统中,进程是最小的运行单位。到了Windows 95/NT等操作系统中,除了进程外还...
在“Java多线程学习总结6”这个主题中,我们可以深入探讨Java多线程的实现、管理及优化。下面将详细阐述相关知识点。 1. **线程的创建方式** - **继承Thread类**:自定义类继承Thread类,并重写run()方法,创建...
下面是对Java多线程学习的详细解析。 1. **多线程概述**: 多线程是指一个程序内可以同时执行多个独立的执行流,每个执行流被称为一个线程。Java通过Thread类来代表线程,每个线程都有自己的生命周期,包括新建、...
Java多线程学习总结.pdf
### Java多线程学习资料知识点解析 #### 一、引言 Java作为一种广泛使用的编程语言,在并发编程领域具有独特的优势。多线程是Java中实现并发处理的核心技术之一,能够显著提升程序的性能和响应性。本文将深入探讨...
### Java多线程编程总结 #### 一、Java线程:概念与原理 - **操作系统中线程和进程的概念** 当前的操作系统通常都是多任务操作系统,多线程是一种实现多任务的方式之一。在操作系统层面,进程指的是内存中运行的...
总结来说,Java多线程学习和FTP上传结合,可以帮助我们构建高效、可控的文件上传服务。通过线程池,我们可以更好地管理并发任务,优化资源使用,提高FTP上传的性能。学习这些内容对于Java开发者尤其重要,尤其是在...
本文档("Java线程学习和总结.htm")可能包含了更多关于线程的实例、源码分析和常见问题解决方案,你可以通过阅读来进一步加深对Java线程的理解。同时,"Java线程学习和总结.files"目录下的文件可能是与文章相关的...
Java多线程是编程中的重要概念,尤其在开发高并发、高性能的应用时不可或缺。本文将深入探讨Java中的线程和进程,以及如何在Java中实现多线程。 首先,理解线程和进程的概念至关重要。线程是操作系统分配CPU时间片...
总结起来,“JAVA多线程编程技术PDF”涵盖了多线程的基本概念、同步机制、线程通信、死锁避免、线程池以及线程安全的集合类等内容。通过深入学习这份资料,开发者可以全面掌握Java多线程编程技术,提升程序的并发...
【Java 多线程学习详细总结】 在Java编程中,多线程是处理并发执行任务的关键技术。本文将深入探讨Java中的多线程概念、实现方式、线程状态转换、线程调度、线程同步以及数据传递等相关知识。 1. **扩展`java.lang...
### Java多线程学习总结 #### 一、Java多线程基本概念 1. **线程状态** - Java中的线程状态分为以下几种:新生(New)、可运行(Runnable)、运行(Running)、等待/阻塞(Waiting/Blocked)以及终止(Terminated...