java线程大总结.docx

上传人:b****9 文档编号:23345472 上传时间:2023-05-16 格式:DOCX 页数:29 大小:21.06KB
下载 相关 举报
java线程大总结.docx_第1页
第1页 / 共29页
java线程大总结.docx_第2页
第2页 / 共29页
java线程大总结.docx_第3页
第3页 / 共29页
java线程大总结.docx_第4页
第4页 / 共29页
java线程大总结.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

java线程大总结.docx

《java线程大总结.docx》由会员分享,可在线阅读,更多相关《java线程大总结.docx(29页珍藏版)》请在冰豆网上搜索。

java线程大总结.docx

java线程大总结

二、

一、

从结果可以看出,信号量仅仅是对池资源进行监控,但不保证线程的安全,因此,在使用时候,应该自己控制线程的安全访问池资源。

阻塞队列是Java5线程新特征中的内容,Java定义了阻塞队列的接口java.util.concurrent.BlockingQueue,阻塞队列的概念是,一个指定长度的队列,如果队列满了,添加新元素的操作会被阻塞等待,直到有空位为止。

同样,当队列为空时候,请求队列元素的操作同样会阻塞等待,直到有可用元素为止。

有了这样的功能,就为多线程的排队等候的模型实现开辟了便捷通道,非常有用。

java.util.concurrent.BlockingQueue继承了java.util.Queue接口,可以参看API文档。

下面给出一个简单应用的例子:

importjava.util.concurrent.BlockingQueue;

importjava.util.concurrent.ArrayBlockingQueue;

/**

*Java线程:

新特征-阻塞队列

*

*@authorleizhimin2009-11-514:

59:

15

*/

publicclassTest{

publicstaticvoidmain(String[]args)throwsInterruptedException{

BlockingQueuebqueue=newArrayBlockingQueue(20);

for(inti=0;i<30;i++){

//将指定元素添加到此队列中,如果没有可用空间,将一直等待(如果有必要)。

bqueue.put(i);

System.out.println("向阻塞队列中添加了元素:

"+i);

}

System.out.println("程序到此运行结束,即将退出----");

}

}

输出结果:

向阻塞队列中添加了元素:

0

向阻塞队列中添加了元素:

1

向阻塞队列中添加了元素:

2

向阻塞队列中添加了元素:

3

向阻塞队列中添加了元素:

4

向阻塞队列中添加了元素:

5

向阻塞队列中添加了元素:

6

向阻塞队列中添加了元素:

7

向阻塞队列中添加了元素:

8

向阻塞队列中添加了元素:

9

向阻塞队列中添加了元素:

10

向阻塞队列中添加了元素:

11

向阻塞队列中添加了元素:

12

向阻塞队列中添加了元素:

13

向阻塞队列中添加了元素:

14

向阻塞队列中添加了元素:

15

向阻塞队列中添加了元素:

16

向阻塞队列中添加了元素:

17

向阻塞队列中添加了元素:

18

向阻塞队列中添加了元素:

19

可以看出,输出到元素19时候,就一直处于等待状态,因为队列满了,程序阻塞了。

这里没有用多线程来演示,没有这个必要。

另外,阻塞队列还有更多实现类,用来满足各种复杂的需求:

ArrayBlockingQueue,DelayQueue,LinkedBlockingQueue,PriorityBlockingQueue,SynchronousQueue,具体的API差别也很小。

对于阻塞栈,与阻塞队列相似。

不同点在于栈是“后入先出”的结构,每次操作的是栈顶,而队列是“先进先出”的结构,每次操作的是队列头。

这里要特别说明一点的是,阻塞栈是Java6的新特征。

Java为阻塞栈定义了接口:

java.util.concurrent.BlockingDeque,其实现类也比较多,具体可以查看JavaAPI文档。

下面看一个简单例子:

importjava.util.concurrent.BlockingDeque;

importjava.util.concurrent.LinkedBlockingDeque;

/**

*Java线程:

新特征-阻塞栈

*

*@authorleizhimin2009-11-515:

34:

29

*/

publicclassTest{

publicstaticvoidmain(String[]args)throwsInterruptedException{

BlockingDequebDeque=newLinkedBlockingDeque(20);

for(inti=0;i<30;i++){

//将指定元素添加到此阻塞栈中,如果没有可用空间,将一直等待(如果有必要)。

bDeque.putFirst(i);

System.out.println("向阻塞栈中添加了元素:

"+i);

}

System.out.println("程序到此运行结束,即将退出----");

}

}

输出结果:

向阻塞栈中添加了元素:

0

向阻塞栈中添加了元素:

1

向阻塞栈中添加了元素:

2

向阻塞栈中添加了元素:

3

向阻塞栈中添加了元素:

4

向阻塞栈中添加了元素:

5

向阻塞栈中添加了元素:

6

向阻塞栈中添加了元素:

7

向阻塞栈中添加了元素:

8

向阻塞栈中添加了元素:

9

向阻塞栈中添加了元素:

10

向阻塞栈中添加了元素:

11

向阻塞栈中添加了元素:

12

向阻塞栈中添加了元素:

13

向阻塞栈中添加了元素:

14

向阻塞栈中添加了元素:

15

向阻塞栈中添加了元素:

16

向阻塞栈中添加了元素:

17

向阻塞栈中添加了元素:

18

向阻塞栈中添加了元素:

19

从上面结果可以看到,程序并没结束,二是阻塞住了,原因是栈已经满了,后面追加元素的操作都被阻塞了。

条件变量是Java5线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量。

但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义。

这里的条件和普通意义上的条件表达式有着天壤之别。

条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。

因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。

条件变量的出现是为了更精细控制线程等待与唤醒,在Java5之前,线程的等待与唤醒依靠的是Object对象的wait()和notify()/notifyAll()方法,这样的处理不够精细。

而在Java5中,一个锁可以有多个条件,每个条件上可以有多个线程等待,通过调用await()方法,可以让线程在该条件下等待。

当调用signalAll()方法,又可以唤醒该条件下的等待的线程。

有关Condition接口的API可以具体参考JavaAPI文档。

条件变量比较抽象,原因是他不是自然语言中的条件概念,而是程序控制的一种手段。

下面以一个银行存取款的模拟程序为例来揭盖Java多线程条件变量的神秘面纱:

有一个账户,多个用户(线程)在同时操作这个账户,有的存款有的取款,存款随便存,取款有限制,不能透支,任何试图透支的操作都将等待里面有足够存款才执行操作。

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

importjava.util.concurrent.locks.Condition;

importjava.util.concurrent.locks.Lock;

importjava.util.concurrent.locks.ReentrantLock;

/**

*Java线程:

条件变量

*

*@authorleizhimin2009-11-510:

57:

29

*/

publicclassTest{

publicstaticvoidmain(String[]args){

//创建并发访问的账户

MyCountmyCount=newMyCount("95599200901215522",10000);

//创建一个线程池

ExecutorServicepool=Executors.newFixedThreadPool

(2);

Threadt1=newSaveThread("张三",myCount,2000);

Threadt2=newSaveThread("李四",myCount,3600);

Threadt3=newDrawThread("王五",myCount,2700);

Threadt4=newSaveThread("老张",myCount,600);

Threadt5=newDrawThread("老牛",myCount,1300);

Threadt6=newDrawThread("胖子",myCount,800);

//执行各个线程

pool.execute(t1);

pool.execute(t2);

pool.execute(t3);

pool.execute(t4);

pool.execute(t5);

pool.execute(t6);

//关闭线程池

pool.shutdown();

}

}

/**

*存款线程类

*/

classSaveThreadextendsThread{

privateStringname;//操作人

privateMyCountmyCount;//账户

privateintx;//存款金额

SaveThread(Stringname,MyCountmyCount,intx){

this.name=name;

this.myCount=myCount;

this.x=x;

}

publicvoidrun(){

myCount.saving(x,name);

}

}

/**

*取款线程类

*/

classDrawThreadextendsThread{

privateStringname;//操作人

privateMyCountmyCount;//账户

privateintx;//存款金额

DrawThread(Stringname,MyCountmyCount,intx){

this.name=name;

this.myCount=myCount;

this.x=x;

}

publicvoidrun(){

myCount.drawing(x,name);

}

}

 

/**

*普通银行账户,不可透支

*/

classMyCount{

privateStringoid;//账号

privateintcash;//账户余额

privateLocklock=newReentrantLock();//账户锁

privateCondition_save=lock.newCondition();//存款条件

privateCondition_draw=lock.newCondition();//取款条件

MyCount(Stringoid,intcash){

this.oid=oid;

this.cash=cash;

}

/**

*存款

*

*@paramx操作金额

*@paramname操作人

*/

publicvoidsaving(intx,Stringname){

lock.lock();//获取锁

if(x>0){

cash+=x;//存款

System.out.println(name+"存款"+x+",当前余额为"+cash);

}

_draw.signalAll();//唤醒所有等待线程。

lock.unlock();//释放锁

}

/**

*取款

*

*@paramx操作金额

*@paramname操作人

*/

publicvoiddrawing(intx,Stringname){

lock.lock();//获取锁

try{

if(cash-x<0){

_draw.await();//阻塞取款操作

}else{

cash-=x;//取款

System.out.println(name+"取款"+x+",当前余额为"+cash);

}

_save.signalAll();//唤醒所有存款操作

}catch(InterruptedExceptione){

e.printStackTrace();

}finally{

lock.unlock();//释放锁

}

}

}

李四存款3600,当前余额为13600

张三存款2000,当前余额为15600

老张存款600,当前余额为16200

老牛取款1300,当前余额为14900

胖子取款800,当前余额为14100

王五取款2700,当前余额为11400

Processfinishedwithexitcode0

假如我们不用锁和条件变量,如何实现此功能呢?

下面是实现代码:

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

/**

*Java线程:

不用条件变量

*

*@authorleizhimin2009-11-510:

57:

29

*/

publicclassTest{

publicstaticvoidmain(String[]args){

//创建并发访问的账户

MyCountmyCount=newMyCount("95599200901215522",10000);

//创建一个线程池

ExecutorServicepool=Executors.newFixedThreadPool

(2);

Threadt1=newSaveThread("张三",myCount,2000);

Threadt2=newSaveThread("李四",myCount,3600);

Threadt3=newDrawThread("王五",myCount,2700);

Threadt4=newSaveThread("老张",myCount,600);

Threadt5=newDrawThread("老牛",myCount,1300);

Threadt6=newDrawThread("胖子",myCount,800);

//执行各个线程

pool.execute(t1);

pool.execute(t2);

pool.execute(t3);

pool.execute(t4);

pool.execute(t5);

pool.execute(t6);

//关闭线程池

pool.shutdown();

}

}

/**

*存款线程类

*/

classSaveThreadextendsThread{

privateStringname;//操作人

privateMyCountmyCount;//账户

privateintx;//存款金额

SaveThread(Stringname,MyCountmyCount,intx){

this.name=name;

this.myCount=myCount;

this.x=x;

}

publicvoidrun(){

myCount.saving(x,name);

}

}

/**

*取款线程类

*/

classDrawThreadextendsThread{

privateStringname;//操作人

privateMyCountmyCount;//账户

privateintx;//存款金额

DrawThread(Stringname,MyCountmyCount,intx){

this.name=name;

this.myCount=myCount;

this.x=x;

}

publicvoidrun(){

myCount.drawing(x,name);

}

}

 

/**

*普通银行账户,不可透支

*/

classMyCount{

privateStringoid;//账号

privateintcash;//账户余额

MyCount(Stringoid,intcash){

this.oid=oid;

this.cash=cash;

}

/**

*存款

*

*@paramx操作金额

*@paramname操作人

*/

publicsynchronizedvoidsaving(intx,Stringname){

if(x>0){

cash+=x;//存款

System.out.println(name+"存款"+x+",当前余额为"+cash);

}

notifyAll();//唤醒所有等待线程。

}

/**

*取款

*

*@paramx操作金额

*@paramname操作人

*/

publicsynchronizedvoiddrawing(intx,Stringname){

if(cash-x<0){

try{

wait();

}catch(InterruptedExceptione1){

e1.printStackTrace();

}

}else{

cash-=x;//取款

System.out.println(name+"取款"+x+",当前余额为"+cash);

}

notifyAll();//唤醒所有存款操作

}

}

输出结果为:

李四存款3600,当前余额为13600

王五取款2700,当前余额为10900

老张存款600,当前余额为11500

老牛取款1300,当前余额为10200

胖子取款800,当前余额为9400

张三存款2000,当前余额为11400

Processfinishedwithexitcode0

结合先前同步代码知识,举一反三,将此例改为同步代码块来实现,代码如下:

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

/**

*Java线程:

改为同步代码块

*

*@authorleizhimin2009-11-510:

57:

29

*/

publicclassTest{

publicstaticvoidmain(String[]args){

//创建并发访问的账户

MyCountmyCount=newMyCount("95599200901215522",10000);

//创建一个线程池

ExecutorServicepool=Executors.newFixedThreadPool

(2);

Threadt1=newSaveThread("张三",myCount,2000);

Threadt2=newSaveThread("李四",myCount,3600);

Threadt3=newDrawThread("王五",myCount,2700);

Threadt4=newSaveThread("老张",myCount,600);

Threadt5=newDrawThread("老牛",myCount,1300);

Threadt6=newDrawThread("胖子",myCount,800);

//执行各个线程

pool.execute(t1);

pool.execute(t2);

pool.execute(t3);

pool.execute(t4);

pool.execute(t5);

pool.execute(t6);

//关闭线程池

pool.shutdown();

}

}

/**

*存款线程类

*/

classSaveThreadextendsThread{

privateStringname;//操作人

privateMyCountmyCount;//账户

privateintx;//存款金额

SaveThread(Stringname,MyCountmyCount,intx){

this.name=name;

this.myCount=myCount;

this.x=x;

}

publicvoidrun(){

myCount.saving(x,name);

}

}

/**

*取款线程类

*/

classDrawThreadextendsThread{

privateStringname;//操作人

privateMyCountmyCount;//账户

privateintx;//存款金额

DrawThread(Stringname,MyCountmyCount,intx){

this.name=name;

this.myCount=myCount;

this.x=x;

}

publicvoidrun(){

myCount.drawing(x,name);

}

}

 

/**

*普通银行账户,不可透支

*/

classMyCount{

privateStringoid;//账号

privateintcash;//账户余额

MyCount(Stringoid,intcash){

this.oid=oid;

this.cash=cash;

}

/**

*存款

*

*@paramx操作金额

*@paramna

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 交规考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1