实验06 线程应用及线程并发库

时间:2019-05-12 15:21:56下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《实验06 线程应用及线程并发库》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《实验06 线程应用及线程并发库》。

第一篇:实验06 线程应用及线程并发库

实验六 线程应用及线程并发库

1.实验内容

实验题1编写一程序,实现如下功能:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,主线程循环100次,如此循环50次。package cn.jp.me;

public class ManageProcedure {

public synchronized void addMainProcedure(){

if(shouldBeSub){ try { wait();

} } for(int i = 1;i <= subTimes;++i){ } shouldBeSub = false;notify();System.out.println(“SubProcedure ” + i);} public synchronized void addSubProcedure(){

if(!shouldBeSub){

try { wait();public ManageProcedure(int subTimes, int mainTimes){

} shouldBeSub = true;this.subTimes = subTimes;this.mainTimes = mainTimes;private boolean shouldBeSub;private int subTimes, mainTimes;} catch(InterruptedException e){

}

} catch(InterruptedException e){

} } } for(int i = 1;i <= mainTimes;++i){ } shouldBeSub = true;notify();System.out.println(“MainProcedure ” + i);package cn.jp.me;

public class SingleProcedure implements Runnable {

@Override public void run(){

if(type.equals(“sub”)){

for(int i = 0;i < times;++i){ } manageProcedure.addSubProcedure();public SingleProcedure(int times, String type,} ManageProcedure manageProcedure){ private int times;private String type;private ManageProcedure manageProcedure;this.times = times;this.type = type;this.manageProcedure = manageProcedure;} else {

for(int i = 0;i < times;++i){ } manageProcedure.addMainProcedure();

} } } package cn.jp.me;

import java.util.Scanner;

public class Text {

} } subThread.start();mainThread.start();Thread subThread = new Thread(subProcedure);Thread mainThread = new Thread(mainProcedure);

ManageProcedure manageProcedure = new ManageProcedure(subTimes, mainTimes);public static void main(String[] args){

int subTimes, mainTimes, totalTimes;Scanner scanner = new Scanner(System.in);System.out.println(“Please Input The SubTimes && MainTimes && The Total Times”);subTimes = scanner.nextInt();mainTimes = scanner.nextInt();totalTimes = scanner.nextInt();SingleProcedure subProcedure = new SingleProcedure(totalTimes, “sub”, manageProcedure);SingleProcedure mainProcedure = new SingleProcedure(totalTimes, “main”, manageProcedure);

实验题2 设计4个线程,其中2个线程每次对count增加1,另外两个线程每次对count减1。

package cn.jp.me;

public class SingleProcedure implements Runnable {

public synchronized void run(){

if(type.equals(“Add”)){ for(int i = 0;i < times;++i){ manageProcedure.add();public SingleProcedure(int runTimes, String typeString,} ManageProcedure manageProcedure){ this.times = runTimes;type = typeString;this.manageProcedure = manageProcedure;private int times;private String type;private ManageProcedure manageProcedure;

}

}

} } for(int i = 0;i < times;++i){ } manageProcedure.substract();} else { package cn.jp.me;public class ManageProcedure {

} package cn.jp.me.text;

import cn.jp.me.ManageProcedure;import cn.jp.jme.SingleProcedure;

public class Text {

Thread addOne = new Thread(singleAdd);public static void main(String[] args){

ManageProcedure manageProcedure = new ManageProcedure();SingleProcedure singleAdd = new SingleProcedure(100 / 2, “Add”, manageProcedure);100 / 2, “substract”, manageProcedure);SingleProcedure singleSubstract = new SingleProcedure(public int getCount(){ } return count;public synchronized void substract(){

}--count;System.out.println(“Thread ” + Thread.currentThread().getName()+ “The Count : ” + getCount());public synchronized void add(){

} ++count;System.out.println(“Thread ” + Thread.currentThread().getName()+ “The Count : ” + getCount());public ManageProcedure(){ } count = 0;private int count;

}

} addOne.setName(“Add One Thread”);Thread addTwo = new Thread(singleAdd);addTwo.setName(“Add Two Thread”);Thread substractOne = new Thread(singleSubstract);substractOne.setName(“Substract One Thread”);Thread substractTwo = new Thread(singleSubstract);substractTwo.setName(“Substract Two Thread”);addOne.start();addTwo.start();substractOne.start();substractTwo.start();

实验题3 CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier。

题目要求:

(1)要在公司大厅集合、然后参观陈云故居;

(2)参观完后集合、准备去淀水湖参观(有3辆车、对应3个线程);

说明:必须等大家都到齐了才能去下个地方、比如说在公司集合、3辆车子都到了才能出发等。要求:用java线程并发库的CyclicBarrier类模拟上述参观过程。

package cn.jp.me;

import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;

public class SingleProcedure implements Runnable {

@Override public void run(){

System.out.println(“ ” + Thread.currentThread().getName()+ “arrives DaTingn And Start Waitting”);public SingleProcedure(CyclicBarrier barrier){ } this.barrier = barrier;private CyclicBarrier barrier;try { barrier.await();} catch(InterruptedException | BrokenBarrierException e){ } System.out.println(“ ” + Thread.currentThread().getName()e.printStackTrace();

}

}

+ “arrives ChenYunGuJunAnd Start Waitting”);try { barrier.await();} catch(InterruptedException | BrokenBarrierException e){ } e.printStackTrace();package cn.jp.me.text;

import java.util.concurrent.CyclicBarrier;

import cn.jp.me.SingleProcedure;

public class Text {

busOne.start();busTwo.start();busThree.start();

Thread busOne = new Thread(component);busOne.setName(“BusOne”);Thread busTwo = new Thread(component);busTwo.setName(“BusTwo”);Thread busThree = new Thread(component);busThree.setName(“BusThree”);

@Override public void run(){ } System.out.println(“All are arrived and Start to next place”);public static void main(String[] args){ CyclicBarrier barrier = new CyclicBarrier(3, new Runnable(){ });SingleProcedure component = new SingleProcedure(barrier);

} }

实验题4 某图书馆邀请一著名作家签名售书,大家去买书,具体情况如下:

(1)买书的读者很多必须排队,作家签好名的书不多(但是他还会看书的销售的情况,一般满了10本(假设)就不会再签了);

(2)有的书还没有签名,这样排在前面的同学就可以买到书、排在后面的就必须等有了签过名的书才能买;

(3)已经签好名的书可以放在ArrayBlockingQueue中,签好名的书不断的向这个队列里放,而买书的读者不断的从里面取书,如没有签名的书,就必须等,书有10本了,作家就停下来休息。买书的每个读者都可以看作一个线程、作家签名也可以看作是一个线程;

(4)排在前面的读者先买。要求:编写程序,模拟上述过程。

package cn.jp.me;

public class Author implements Runnable {

public Author(CommonData data){ } this.data = data;private CommonData data;

}

package cn.jp.me;

public class Reader implements Runnable {

@Override public void run(){

for(int i = 0;i < data.getTimes();++i){

try { buyABook();} catch(InterruptedException e){ public Reader(CommonData data){ } this.data = data;private CommonData data;private void SignABook()throws InterruptedException {

} while(data.getNumber()== 10){

} data.setSign(data.getSign()+ 1);;System.out.println(“The Author Sign NO.” + data.getSign()+ “ book”);data.put(“The Author Sign No.” + data.getSign()+ “Book”);System.out.println(“There Are ” + data.getNumber()+ “Books Signed”);while(data.getNumber()== 10){

} System.out.println(“There Are 10 Books.The Author Chould Rest A While”);Thread.sleep(4000);System.out.println(“There Are 10 Books.The Author Chould Rest A While”);Thread.sleep(4000);} @Override public void run(){

for(int i = 0;i < data.getTimes();++i){

} try {

} SignABook();e.printStackTrace();} catch(InterruptedException e){

}

}

} } e.printStackTrace();private void buyABook()throws InterruptedException {

} while(data.getNumber()== 0){

} data.setBuy(data.getBuy()+ 1);System.out.println(“Buy The No.” + data.getBuy()+ “ Book”);System.out.println(data.getFirBook()+ “Be Bought”);System.out.println(“There Are ” + data.getNumber()+ “Books Signed”);while(data.getNumber()== 0){

} System.out.println(“There Does Not Exist Books Signed.Must Wait……”);Thread.sleep(3000);System.out.println(“There Does Not Exist Books Signed.Must Wait……”);Thread.sleep(3000);package cn.jp.me;

import java.util.concurrent.ArrayBlockingQueue;

public class CommonData {

public String getFirBook()throws InterruptedException { } return queue.take();public int getNumber(){ } return queue.size();public CommonData(int times){

} queue = new ArrayBlockingQueue(10);this.times = times;buy = 0;sign = 0;private ArrayBlockingQueue queue;private int buy, sign;private int times;

} public void put(String elem)throws InterruptedException { } public int getTimes(){ } public int getBuy(){ } public void setBuy(int buy){ } public int getSign(){ } public void setSign(int sign){ } this.sign = sign;return sign;this.buy = buy;return buy;return times;queue.put(elem);package cn.jp.me;

public class Text {

} public static void main(String[] args){

} CommonData data = new CommonData(100);Author author = new Author(data);Reader reader = new Reader(data);new Thread(author).start();new Thread(reader).start();

实验题5模拟拥有一定数量账户的银行,把随机产生的钱在不同账号之间进行转移交易。每个账号都有一个线程,在每笔交易中,都会从线程所服务的账户中随机取出一定数额的钱转移到另一个随机账户中。

提示: 设计一个Bank类,它有一个transfer方法,该方法将一定数额的钱从一个账户转移到另一个账户,如源账户没有足够余额,该方法直接返回。

package cn.jp.me;

import java.text.Normalizer.Form;

public class Bank {

}

package cn.jp.me;public int getTotalAccountNum(){ } return totalAccountNum;public void setBalance(int accountNo, int num){ } balance[accountNo] = num;public synchronized void transfer(int from, int to, int amount){

} System.out.println(“The Change From ” + from + “ To ” + to);if(balance[from] >= amount){

} System.out.println();System.out.println(“Before Transfer The Balance Of ” + from + “ : ” + balance[from] + “;Of ” + to + “ : ” + balance[to]);System.out.println(“The Change Amount : ” + amount);balance[from]-= amount;balance[to] += amount;System.out.println(“After Transfer The Balance Of ” + from + “ : ” + balance[from] + “;Of ” + to + “ : ” + balance[to]);public Bank(int accountNum){

} totalAccountNum = accountNum;balance = new int[accountNum + 1];private int totalAccountNum;private int[] balance;} else { System.out.println(“The Account ” + from + “'s Balance Is Not Enough”);

import java.util.Random;

import javax.security.auth.login.AccountException;

public class Account implements Runnable {

} package cn.jp.me;

import java.util.Random;import java.util.Scanner;

public class Text {

} Bank bank = new Bank(accountNum);for(int i = 1;i <= accountNum;++i){

} new Thread(new Account(i, random.nextInt(1000000)+ 0, bank)).start();

System.out.println(“Please Input The Number Of Account You Want To Imitate :”);accountNum = scanner.nextInt();public static void main(String[] args){

Random random = new Random();int accountNum;Scanner scanner = new Scanner(System.in);} bank.transfer(accountNo, to, changeNum);@Override public synchronized void run(){ to = random.nextInt(bank.getTotalAccountNum()+ 1);changeNum = random.nextInt(1000000)+ 0;public Account(int accountNo, int initialValue, Bank bank){

} this.accountNo = accountNo;this.bank = bank;bank.setBalance(accountNo, initialValue);private int accountNo;private Bank bank;private static Random random = new Random();int to, changeNum;}

第二篇:Java线程总结

Java线程总结

首先要理解线程首先需要了解一些基本的东西,我们现在所使用的大多数操作系统都属于多任务,分时操作系统。正是由于这种操作系统的出现才有了多线程这个概念。我们使用的windows,linux就属于此列。什么是分时操作系统呢,通俗一点与就是可以同一时间执行多个程序的操作系统,在自己的电脑上面,你是不是一边听歌,一边聊天还一边看网页呢?但实际上,并不上cpu在同时执行这些程序,cpu只是将时间切割为时间片,然后将时间片分配给这些程序,获得时间片的程序开始执行,不等执行完毕,下个程序又获得时间片开始执行,这样多个程序轮流执行一段时间,由于现在cpu的高速计算能力,给人的感觉就像是多个程序在同时执行一样。

一般可以在同一时间内执行多个程序的操作系统都有进程的概念.一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间,一组系统资源.在进程概念中,每一个进程的内部数据和状态都是完全独立的.因此可以想像创建并执行一个进程的系统开像是比较大的,所以线程出现了。在java中,程序通过流控制来执行程序流,程序中单个顺序的流控制称为线程,多线程则指的是在单个程序中可以同时运行多个不同的线程,执行不同的任务.多线程意味着一个程序的多行语句可以看上去几乎在同一时间内同时运行.(你可以将前面一句话的程序换成进程,进程是程序的一次执行过程,是系统运行程序的基本单位)

线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多个线程是共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈.所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多,正因如此,线程也被称为轻负荷进程(light-weight process).一个进程中可以包含多个线程.多任务是指在一个系统中可以同时运行多个程序,即有多个独立运行的任务,每个任务对应一个进程,同进程一样,一个线程也有从创建,运行到消亡的过程,称为线程的生命周期.用线程的状态(state)表明线程处在生命周期的哪个阶段.线程有创建,可运行,运行中,阻塞,死亡五中状态.通过线程的控制与调度可使线程在这几种状态间转化每个程序至少自动拥有一个线程,称为主线程.当程序加载到内存时,启动主线程.[线程的运行机制以及调度模型]

java中多线程就是一个类或一个程序执行或管理多个线程执行任务的能力,每个线程可以独立于其他线程而独立运行,当然也可以和其他线程协同运行,一个类控制着它的所有线程,可以决定哪个线程得到优先级,哪个线程可以访问其他类的资源,哪个线程开始执行,哪个保持休眠状态。下面是线程的机制图:

Page 1 of 16

线程的状态表示线程正在进行的活动以及在此时间段内所能完成的任务.线程有创建,可运行,运行中,阻塞,死亡五中状态.一个具有生命的线程,总是处于这五种状态之一: 1.创建状态

使用new运算符创建一个线程后,该线程仅仅是一个空对象,系统没有分配资源,称该线程处于创建状态(new thread)2.可运行状态

使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,使该线程处于可运行状态(Runnable)3.运行中状态

Java运行系统通过调度选中一个Runnable的线程,使其占有CPU并转为运行中状态(Running).此时,系统真正执行线程的run()方法.4.阻塞状态

一个正在运行的线程因某种原因不能继续运行时,进入阻塞状态(Blocked)5.死亡状态

线程结束后是死亡状态(Dead)

同一时刻如果有多个线程处于可运行状态,则他们需要排队等待CPU资源.此时每个线程自动获得一个线程的优先级(priority),优先级的高低反映线程的重要或紧急程度.可运行状态的线程按优先级排队,线程调度依据优先级基础上的“先到先服务”原则.线程调度管理器负责线程排队和CPU在线程间的分配,并由线程调度算法进行调度.当线程调度管理器选种某个线程时,该线程获得CPU资源而进入运行状态.线程调度是先占式调度,即如果在当前线程执行过程中一个更高优先级的线程进入可运行状态,则这个线程立即被调度执行.先占式调度分为:独占式和分时方式.独占方式下,当前执行线程将一直执行下去,直 到执行完毕或由于某种原因主动放弃CPU,或CPU被一个更高优先级的线程抢占

分时方式下,当前运行线程获得一个时间片,时间到时,即使没有执行完也要让出

Page 2 of 16

CPU,进入可运行状态,等待下一个时间片的调度.系统选中其他可运行状态的线程执行

分时方式的系统使每个线程工作若干步,实现多线程同时运行

另外请注意下面的线程调度规则(如果有不理解,不急,往下看): ①如果两个或是两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的(Synchronized),如果对象更新影响到只读方法,那么只度方法也应该定义为同步的

②如果一个线程必须等待一个对象状态发生变化,那么它应该在对象内部等待,而不是在外部等待,它可以调用一个被同步的方法,并让这个方法调用wait()③每当一个方法改变某个对象的状态的时候,它应该调用notifyAll()方法,这给等待队列的线程提供机会来看一看执行环境是否已发生改变

④记住wait(),notify(),notifyAll()方法属于Object类,而不是Thread类,仔细检查看是否每次执行wait()方法都有相应的notify()或notifyAll()方法,且它们作用与相同的对象 在java中每个类都有一个主线程,要执行一个程序,那么这个类当中一定要有main方法,这个man方法也就是java class中的主线程。你可以自己创建线程,有两种方法,一是继承Thread类,或是实现Runnable接口。一般情况下,最好避免继承,因为java中是单根继承,如果你选用继承,那么你的类就失去了弹性,当然也不能全然否定继承Thread,该方法编写简单,可以直接操作线程,适用于单重继承情况。至于选用那一种,具体情况具体分析。

eg.继承Thread

public class MyThread_1 extends Thread{ public void run(){ //some code } }

eg.实现Runnable接口

public class MyThread_2 implements Runnable { public void run(){ //some code } }

Page 3 of 16

当使用继承创建线程,这样启动线程:

new MyThread_1().start()

当使用实现接口创建线程,这样启动线程:

new Thread(new MyThread_2()).start()

注意,其实是创建一个线程实例,并以实现了Runnable接口的类为参数传入这个实例,当执行这个线程的时候,MyThread_2中run里面的代码将被执行。下面是完成的例子:

public class MyThread implements Runnable { public void run(){ System.out.println(“My Name is ”+Thread.currentThread().getName());} public static void main(String[] args){ new Thread(new MyThread()).start();} }

执行后将打印出: My Name is Thread-0

你也可以创建多个线程,像下面这样

new Thread(new MyThread()).start();new Thread(new MyThread()).start();new Thread(new MyThread()).start();

那么会打印出:

My Name is Thread-0 My Name is Thread-1

Page 4 of 16

My Name is Thread-2

看了上面的结果,你可能会认为线程的执行顺序是依次执行的,但是那只是一般情况,千万不要用以为是线程的执行机制;影响线程执行顺序的因素有几点:首先看看前面提到的优先级别

public class MyThread implements Runnable { public void run(){ System.out.println(“My Name is ”+Thread.currentThread().getName());} public static void main(String[] args){ Thread t1=new Thread(new MyThread());Thread t2=new Thread(new MyThread());Thread t3=new Thread(new MyThread());

t2.setPriority(Thread.MAX_PRIORITY);//赋予最高优先级

t1.start();t2.start();t3.start();} }

再看看结果:

My Name is Thread-1 My Name is Thread-0 My Name is Thread-2

Page 5 of 16

线程的优先级分为10级,分别用1到10的整数代表,默认情况是5。上面的t2.setPriority(Thread.MAX_PRIORITY)等价与t2.setPriority(10)

然后是线程程序本身的设计,比如使用sleep,yield,join,wait等方法(详情请看JDKDocument)

public class MyThread implements Runnable { public void run(){

try {

int sleepTime =(int)(Math.random()* 100);// 产生随机数字,Thread.currentThread().sleep(sleepTime);// 让其休眠一定时间,时间又上面sleepTime决定

// public static void sleep(long millis)throw InterruptedException

//(API)

System.out.println(Thread.currentThread().getName()+ “ 睡了 ”

+ sleepTime);

} catch(InterruptedException ie)

// 由于线程在休眠可能被中断,所以调用sleep方法的时候需要捕捉异常

Page 6 of 16

{

ie.printStackTrace();

} }

public static void main(String[] args){

Thread t1 = new Thread(new MyThread());

Thread t2 = new Thread(new MyThread());

Thread t3 = new Thread(new MyThread());

t1.start();

t2.start();

t3.start();} }

执行后观察其输出: Thread-0 睡了 11 Thread-2 睡了 48 Thread-1 睡了 69

上面的执行结果是随机的,再执行很可能出现不同的结果。由于上面我在run中添加了休眠语句,当线程休眠的时候就会让出cpu,cpu将会选择执行处于runnable状态中的其他线程,当然也可能出现这种情况,休眠的Thread立即进入了runnable状态,cpu再次执行它。[线程组概念] 线程是可以被组织的,java中存在线程组的概念,每个线程都是一个线程组的成员,线程组把多个线程集成为一个对象,通过线程组可以同时对其中的多个线程进行操作,如启动一个线程组的所有线程等.Java的线程组由java.lang包中的Thread——Group类实现.ThreadGroup类用来管理一组线程,包括:线程的数目,线程间的关系,线程正在执行的操作,以及线程将要启动或终止时间等.线程组还可以包含线程组.在Java的应用程序中,最高层的线程组是名位main的线程组,在main中还可以加入线程或

Page 7 of 16

线程组,在mian的子线程组中也可以加入线程和线程组,形成线程组和线程之间的树状继承关系。像上面创建的线程都是属于main这个线程组的。借用上面的例子,main里面可以这样写:

public static void main(String[] args){

/***************************************

* ThreadGroup(String name)ThreadGroup(ThreadGroup parent, String name)

***********************************/

ThreadGroup group1 = new ThreadGroup(“group1”);

ThreadGroup group2 = new ThreadGroup(group1, “group2”);

Thread t1 = new Thread(group2, new MyThread());

Thread t2 = new Thread(group2, new MyThread());

Thread t3 = new Thread(group2, new MyThread());

t1.start();

t2.start();

t3.start();} 线程组的嵌套,t1,t2,t3被加入group2,group2加入group1。

Page 8 of 16

另外一个比较多就是关于线程同步方面的,试想这样一种情况,你有一笔存款在银行,你在一家银行为你的账户存款,而你的妻子在另一家银行从这个账户提款,现在你有1000块在你的账户里面。你存入了1000,但是由于另一方也在对这笔存款进行操作,人家开始执行的时候只看到账户里面原来的1000元,当你的妻子提款1000元后,你妻子所在的银行就认为你的账户里面没有钱了,而你所在的银行却认为你还有2000元。看看下面的例子:

class BlankSaving // 储蓄账户 { private static int money = 10000;

public void add(int i){

money = money + i;

System.out.println(“Husband 向银行存入了 [¥” + i + “]”);}

public void get(int i){

money = money-i;

System.out.println(“Wife 向银行取走了 [¥” + i + “]”);

if(money < 0)

System.out.println(“余额不足!”);}

Page 9 of 16

public int showMoney(){

return money;} }

class Operater implements Runnable { String name;BlankSaving bs;

public Operater(BlankSaving b, String s){

name = s;

bs = b;

}

public static void oper(String name, BlankSaving bs){

if(name.equals(“husband”)){

try {

for(int i = 0;i < 10;i++){

Page 10 of 16

Thread.currentThread().sleep((int)(Math.random()* 300));

bs.add(1000);

}

} catch(InterruptedException e){

}

} else {

try {

for(int i = 0;i < 10;i++){

Thread.currentThread().sleep((int)(Math.random()* 300));

bs.get(1000);

}

} catch(InterruptedException e){

}

} }

public void run(){

oper(name, bs);}

Page 11 of 16

}

public class BankTest { public static void main(String[] args)throws InterruptedException {

BlankSaving bs = new BlankSaving();

Operater o1 = new Operater(bs, “husband”);

Operater o2 = new Operater(bs, “wife”);

Thread t1 = new Thread(o1);

Thread t2 = new Thread(o2);

t1.start();

t2.start();

Thread.currentThread().sleep(500);} }

下面是其中一次的执行结果:

---------first--------------Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000]

Page 12 of 16

Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Husband 向银行存入了 [¥1000]

看到了吗,这可不是正确的需求,在husband还没有结束操作的时候,wife就插了进来,这样很可能导致意外的结果。解决办法很简单,就是将对数据进行操作方法声明为synchronized,当方法被该关键字声明后,也就意味着,如果这个数据被加锁,只有一个对象得到这个数据的锁的时候该对象才能对这个数据进行操作。也就是当你存款的时候,这笔账户在其他地方是不能进行操作的,只有你存款完毕,银行管理人员将账户解锁,其他人才能对这个账户进行操作。

修改public static void oper(String name,BlankSaving bs)为public static void oper(String name,BlankSaving bs),再看看结果:

Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Husband 向银行存入了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000] Wife 向银行取走了 [¥1000]

当丈夫完成操作后,妻子才开始执行操作,这样的话,对共享对象的操作就不会有问题了。

[wait and notify] 你可以利用这两个方法很好的控制线程的执行流程,当线程调用wait方法后,线

Page 13 of 16

程将被挂起,直到被另一线程唤醒(notify)或则是如果wait方法指定有时间得话,在没有被唤醒的情况下,指定时间时间过后也将自动被唤醒。但是要注意一定,被唤醒并不是指马上执行,而是从组塞状态变为可运行状态,其是否运行还要看cpu的调度。事例代码:

class MyThread_1 extends Thread {

Object lock;

public MyThread_1(Object o){

lock = o;}

public void run(){

try {

synchronized(lock){

System.out.println(“Enter Thread_1 and wait”);

lock.wait();

System.out.println(“be notified”);

}

} catch(InterruptedException e){

} }

Page 14 of 16

}

class MyThread_2 extends Thread { Object lock;

public MyThread_2(Object o){

lock = o;}

public void run(){

synchronized(lock){

System.out.println(“Enter Thread_2 and notify”);

lock.notify();

} } }

public class MyThread { public static void main(String[] args){

int[] in = new int[0];// notice

MyThread_1 t1 = new MyThread_1(in);

Page 15 of 16

MyThread_2 t2 = new MyThread_2(in);

t1.start();

t2.start();} }

执行结果如下:

Enter Thread_1 and wait Enter Thread_2 and notify Thread_1 be notified

可能你注意到了在使用wait and notify方法得时候我使用了synchronized块来包装这两个方法,这是由于调用这两个方法的时候线程必须获得锁,也就是上面代码中的lock[],如果你不用synchronized包装这两个方法的得话,又或则锁不一是同一把,比如在MyThread_2中synchronized(lock)改为synchronized(this),那么执行这个程序的时候将会抛出java.lang.IllegalMonitorStateException执行期异常。另外wait and notify方法是Object中的,并不在Thread这个类中。最后你可能注意到了这点:int[] in=new int[0];为什么不是创建new Object而是一个0长度的数组,那是因为在java中创建一个0长度的数组来充当锁更加高效。

Page 16 of 16

第三篇:Java线程编程总结

线程编程方面

60、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?

答:有两种实现方法,分别是继承Thread类与实现Runnable接口 用synchronized关键字修饰同步方法

反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被“挂起”的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。61、sleep()和 wait()有什么区别? 答:sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

62、同步和异步有何异同,在什么情况下分别使用他们?举例说明。

答:如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取。

当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。63、启动一个线程是用run()还是start()? 答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。

64、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 答:不能,一个对象的一个synchronized方法只能由一个线程访问。

我认为:其他线程可以进入非synchronized方法,但不能进入这个对象的synchronized方法。65、请说出你所知道的线程同步的方法。

答:wait():使一个线程处于等待状态,并且释放所持有的对象的lock。

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。

66、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 答:多线程有两种实现方法,分别是继承Thread类与实现Runnable接口 同步的实现方面有两种,分别是synchronized,wait与notify 67、线程的基本概念、线程的基本状态以及状态之间的关系

答:线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。

Java中的线程有四种状态分别是:运行、就绪、挂起、结束

68、简述synchronized和java.util.concurrent.locks.Lock的异同 ? 答:主要相同点:Lock能完成synchronized所实现的所有功能

主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。

Jsp方面

69、forward 和redirect的区别

答:forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。

redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。70、jsp有哪些内置对象?作用分别是什么?

答:JSP共有以下9种基本内置组件(可与ASP的6种内部组件相对应):

request 用户端请求,此请求会包含来自GET/POST请求的参数

response 网页传回用户端的回应

pageContext 网页的属性是在这里管理

session 与请求有关的会话期

application servlet 正在执行的内容

out 用来传送回应的输出 config servlet的构架部件

page JSP网页本身

exception 针对错误网页,未捕捉的例外

71、jsp有哪些动作?作用分别是什么? 答:JSP共有以下6种基本动作

jsp:include:在页面被请求的时候引入一个文件。

jsp:useBean:寻找或者实例化一个JavaBean。

jsp:setProperty:设置JavaBean的属性。

jsp:getProperty:输出某个JavaBean的属性。

jsp:forward:把请求转到一个新的页面。

jsp:plugin:根据浏览器类型为Java插件生成OBJECT或EMBED标记 72、JSP中动态INCLUDE与静态INCLUDE的区别?

答:动态INCLUDE用jsp:include动作实现

它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数

静态INCLUDE用include伪码实现,定不会检查所含文件的变化,适用于包含静态页面

<%@ include file=“included.htm” %> 73、两种跳转方式分别是什么?有什么区别? 答:有两种,分别为:

前者页面不会转向include所指的页面,只是显示该页的结果,主页面还是原来的页面。执行完后还会回来,相当于函数调用。并且可以带参数.后者完全转向新页面,不会再回来。相当于go to 语句。

74、JSP的内置对象及方法。

答:request表示HttpServletRequest对象。它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie, header, 和session数据的有用的方法。

response表示HttpServletResponse对象,并提供了几个用于设置送回 浏览器的响应的方法(如cookies,头信息等)

out对象是javax.jsp.JspWriter的一个实例,并提供了几个方法使你能用于向浏览器回送输出结果。

pageContext表示一个javax.servlet.jsp.PageContext对象。它是用于方便存取各种范围的名字空间、servlet相关的对象的API,并且包装了通用的servlet相关功能的方法。

session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息

applicaton 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和servlet环境的信息

config表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。page表示从该页面产生的一个servlet实例

Servlet方面

75、说一说Servlet的生命周期?

答:servlet有良好的生存期的定义,包括加载和实例化、初始化、处理请求以及服务结束。这个生存期由javax.servlet.Servlet接口的init,service和destroy方法表达。Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。

与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。

76、JAVA SERVLET API中forward()与redirect()的区别?

答:前者仅是容器中控制权的转向,在客户端浏览器地址栏中不会显示出转向后的地址;后者则是完全的跳转,浏览器将会得到跳转的地址,并重新发送请求链接。这样,从浏览器的地址栏中可以看到跳转后的链接地址。所以,前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接。在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用sendRedirect()方法。77、Servlet的基本架构 答:

public class ServletName extends HttpServlet { public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { } public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException { } }

78、什么情况下调用doGet()和doPost()?

答:Jsp页面中的form标签里的method属性为get时调用doGet(),为post时调用doPost()。79、servlet的生命周期

答:web容器加载servlet,生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现,根据请求的不同调用不同的do***()方法。结束服务,web容器调用servlet的destroy()方法。

80、如何现实servlet的单线程模式 答:<%@ page isThreadSafe=“false”%> 81、页面间对象传递的方法

答:request,session,application,cookie等

82、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?

答:JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达。JSP编译后是“类servlet”。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。83、四种会话跟踪技术

答:会话作用域ServletsJSP 页面描述

page否是代表与一个页面相关的对象和属性。一个页面由一个编译好的 Java servlet 类(可以带有任何的 include 指令,但是没有 include 动作)表示。这既包括 servlet 又包括被编译成 servlet 的 JSP 页面

request是是代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件(由于 forward 指令和 include 动作的关系)

session是是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性。一个 Web 会话可以也经常会跨越多个客户机请求

application是是代表与整个 Web 应用程序相关的对象和属性。这实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域 84、Request对象的主要方法 答:

setAttribute(String name,Object):设置名字为name的request的参数值 getAttribute(String name):返回由name指定的属性值

getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例 getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组 getCharacterEncoding():返回请求中的字符编码方式 getContentLength():返回请求的Body的长度

getHeader(String name):获得HTTP协议定义的文件头信息 getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例 getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例 getInputStream():返回请求的输入流,用于获得请求中的数据 getMethod():获得客户端向服务器端传送数据的方法

getParameter(String name):获得客户端传送给服务器端的有name指定的参数值

getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例 getParameterValues(String name):获得有name指定的参数的所有值 getProtocol():获取客户端向服务器端传送数据所依据的协议名称 getQueryString():获得查询字符串

getRequestURI():获取发出请求字符串的客户端地址 getRemoteAddr():获取客户端的IP地址 getRemoteHost():获取客户端的名字

getSession([Boolean create]):返回和请求相关Session getServerName():获取服务器的名字

getServletPath():获取客户端所请求的脚本文件的路径 getServerPort():获取服务器的端口号

removeAttribute(String name):删除请求中的一个属性

85、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串? 答:

Public String translate(String str){ String tempStr = “";try { tempStr = new String(str.getBytes(”ISO-8859-1“), ”GBK");tempStr = tempStr.trim();} catch(Exception e){ System.err.println(e.getMessage());} return tempStr;} 86、Servlet执行时一般实现哪几个方法? 答:

public void init(ServletConfig config)public ServletConfig getServletConfig()public String getServletInfo()public void service(ServletRequest request,ServletResponse response)public void destroy()

Jdbc、Jdo方面88、Jdo是什么?

87、Class.forName的作用?为什么要用?

答:调用该访问返回一个以字符串指定类名的类的对象。答:JDO是Java对象持久化的新的规范,为java data object的简称,也是一个用于存取某种数据仓库中的对象的标准化API。JDO提供了透明的对象存储,因此对开发人员来说,存储数据对象完全不需要额外的代码(如JDBC API的使用)。这些繁琐的例行工作已经转移到JDO产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,JDO很灵活,因为它可以在任何数据底层上运行。JDBC只是面向关系数据库(RDBMS)JDO更通用,提供到任何数据底层的存储功能,比如关系数据库、文件、XML以及对象数据库(ODBMS)等等,使得应用可移植性更强。89、说出数据连接池的工作机制是什么? 答:J2EE服务器启动时会建立一定数量的池连接,并一直维持不少于此数目的池连接。客户端程序需要连接时,池驱动程序会返回一个未使用的池连接并将其表记为忙。如果当前没有空闲连接,池驱动程序就新建一定数量的连接,新建连接的数量有配置参数决定。当使用的池连接调用完成后,池驱动程序将此连接表记为空闲,其他调用就可以使用这个连接。90、Jdo是什么? 答:JDO是Java对象持久化的新的规范,为java data object的简称,也是一个用于存取某种数据仓库中的对象的标准化API。JDO提供了透明的对象存储,因此对开发人员来说,存储数据对象完全不需要额外的代码(如JDBC API的使用)。这些繁琐的例行工作已经转移到JDO产品提供商身上,使开发人员解脱出来,从而集中时间和精力在业务逻辑上。另外,JDO很灵活,因为它可以在任何数据底层上运行。JDBC只是面向关系数据库(RDBMS)JDO更通用,提供到任何数据底层的存储功能,比如关系数据库、文件、XML以及对象数据库(ODBMS)等等,使得应用可移植性更强。

Xml方面

91、xml有哪些解析技术?区别是什么? 答:有DOM,SAX,STAX等

DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问。

SAX:不现于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问 STAX:Streaming API for XML(StAX)92、你在项目中用到了xml技术的哪些方面?如何实现的?

答:用到了数据存贮,信息配置两方面。在做数据交换平台时,将不能数据源的数据组装成XML文件,然后将XML文件压缩打包加密后通过网络传送给接收者,接收解密与解压缩后再同XML文件中还原相关信息进行处理。在做软件配置时,利用XML可以很方便的进行,软件的各种配置参数都存贮在XML文件中。

93、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 答:a: 两种形式 dtd schema,b: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发展schema的根本目的),c:有DOM,SAX,STAX等

DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问

SAX:不现于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问 STAX:Streaming API for XML(StAX)

第四篇:Weblogic线程堆栈获取方式小结

Weblogic线程堆栈获取方式小结

当服务器挂起,崩溃或者性能底下时,就需要抓取服务器的线程堆栈(Thread Dump)用于后续的分析.Thread dump提供了当前活动的线程的快照.它提供了JVM中所有Java线程的栈跟踪信息,有很多方式可用于获取Thread Dump, 一些是操作系统特定的命令.操作系统命令获取ThreadDump: Windows: 转向服务器的标准输出窗口并按下Control + Break组合键, 之后需要将线程堆栈复制到文件中

UNIX/ Linux 首先查找到服务器的进程号(process id), 然后获取堆栈.1.ps –ef | grep java 2.kill-3

注意一定要谨慎, 一步不慎就可能让服务器进程被杀死!JVM 自带的工具获取线程堆栈: JDK自带命令行工具获取PID并做ThreadDump: 1.jps 2.jstack

3.使用JVisualVM: Threads 标签页àThreadDump按钮.WebLogic 自带的获取 thread dump的工具: 1.webLogic.Admin 工具

a.打开命令提示符, 通过运行/bin/setDomain.env设置相关类路径

b.执行下面的命令

java weblogic.Admin-url t3://localhost:7001-username weblogic-password weblogic1 THREAD_DUMP 注意: Thread Dump 会打印到标准输出, 如nohup日志或者进程窗口.2.使用 Admin Console a.登录 Admin Console , 点击对应的服务器 b.点击Server à Monitoring àThreads c.点击: Dump Thread Stack 按钮 3.使用WLST(WebLogic Scripting Tool)connect(‘weblogic’,'weblogic1’,’t3://localhost:7001’)cd(‘Servers’)cd(‘AdminServer’)threadDump()disconnect()exit()注意: 线程堆栈将会保存在运行wlst的当前目录下.4.使用utils.ThreadDumper 用法: C:beawlserver_10.3serverlib>java utils.ThreadDumper Broadcast Thread

dumps

disabled:

must

specify

-cp

weblogic.jar weblogic.debug.dumpThreadAddr and weblogic.debug.dumpThreadPort Exception in thread “main” java.lang.IllegalArgumentException: Port out of range :-1 at java.net.DatagramPacket.setPort(Unknown Source)at java.net.DatagramPacket.(Unknown Source)at java.net.DatagramPacket.(Unknown Source)at utils.ThreadDumper.sendDumpMsg(ThreadDumper.java:124)at utils.ThreadDumper.main(ThreadDumper.java:145)5.如果服务器是作为Windows服务的方式运行, 请运行下列命令: WL_HOMEbinbeasvc-dump-svcname:service-name 其它一些获取Thread Dump的工具有jrcmd, jrmc(JRockit VM自带),Samurai, JProfiler等, 还可通过JMX编程的方式获取, 如JDK自带示例代码: $JAVA_HOMEdemomanagementFullThreadDump

第五篇:Java程序员必须掌握的线程知识

Java程序员必须掌握的线程知识 Callable和Future Callable和Future出现的原因

创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口。

这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦。

而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

Callable和Future介绍

Callable接口代表一段可以调用并返回结果的代码;Future接口表示异步任务,是还没有完成的任务给出的未来结果。所以说Callable用于产生结果,Future用于获取结果。

Callable接口使用泛型去定义它的返回类型。Executors类提供了一些有用的方法在线程池中执行Callable内的任务。由于Callable任务是并行的(并行就是整体看上去是并行的,其实在某个时间点只有一个线程在执行),我们必须等待它返回的结果。

java.util.concurrent.Future对象为我们解决了这个问题。在线程池提交Callable任务后返回了一个Future对象,使用它可以知道Callable任务的状态和得到Callable返回的执行结果。Future提供了get()方法让我们可以等待Callable结束并获取它的执行结果。

Callable与Runnable

java.lang.Runnable吧,它是一个接口,在它里面只声明了一个run()方法:

publicinterfaceRunnable{

publicabstractvoid run();}

由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。

Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call():

publicinterfaceCallable{

/**

* Computes a result, or throws an exception if unable to do so.*

* @return computed result

* @throws Exception if unable to compute a result

*/

V call()throwsException;}

可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。

那么怎么使用Callable呢?

一般情况下是配合ExecutorService来使用的,在ExecutorService接口中声明了若干个submit方法的重载版本:

Future submit(Callable task); Future submit(Runnable task, T result);Future submit(Runnable task);

第一个submit方法里面的参数类型就是Callable。

暂时只需要知道Callable一般是和ExecutorService配合来使用的,具体的使用方法讲在后面讲述。

一般情况下我们使用第一个submit方法和第三个submit方法,第二个submit方法很少使用。

Future

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

Future类位于java.util.concurrent包下,它是一个接口:

publicinterfaceFuture{

boolean cancel(boolean mayInterruptIfRunning);

boolean isCancelled();

boolean isDone();

V get()throwsInterruptedException,ExecutionException;

V get(long timeout,TimeUnit unit)

throwsInterruptedException,ExecutionException,TimeoutException;}

在Future接口中声明了5个方法,下面依次解释每个方法的作用:

cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。

isDone方法表示任务是否已经完成,若任务完成,则返回true;

get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;

get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。

也就是说Future提供了三种功能:

1)判断任务是否完成;

2)能够中断任务;

3)能够获取任务执行结果。

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。FutureTask

FutureTask实现了RunnableFuture接口,这个接口的定义如下:

publicinterfaceRunnableFutureextendsRunnable,Future{

void run();}

可以看到这个接口实现了Runnable和Future接口,接口中的具体实现由FutureTask来实现。这个类的两个构造方法如下 :

publicFutureTask(Callable callable){

if(callable ==null)

thrownewNullPointerException();

sync =newSync(callable);

}

publicFutureTask(Runnable runnable, V result){

sync =newSync(Executors.callable(runnable, result));

} 如上提供了两个构造函数,一个以Callable为参数,另外一个以Runnable为参数。这些类之间的关联对于任务建模的办法非常灵活,允许你基于FutureTask的Runnable特性(因为它实现了Runnable接口),把任务写成Callable,然后封装进一个由执行者调度并在必要时可以取消的FutureTask。

FutureTask可以由执行者调度,这一点很关键。它对外提供的方法基本上就是Future和Runnable接口的组合:get()、cancel、isDone()、isCancelled()和run(),而run()方法通常都是由执行者调用,我们基本上不需要直接调用它。

一个FutureTask的例子

publicclassMyCallableimplementsCallable{

privatelong waitTime;

publicMyCallable(int timeInMillis){

this.waitTime=timeInMillis;

}

@Override

publicString call()throwsException{ Thread.sleep(waitTime);

//return the thread name executing this callable task

returnThread.currentThread().getName();

}

}

publicclassFutureTaskExample{

publicstaticvoid main(String[] args){

MyCallable callable1 =newMyCallable(1000);// 要执行的任务

MyCallable callable2 =newMyCallable(2000);

FutureTask futureTask1 =newFutureTask(callable1);// 将Callable写的任务封装到一个由执行者调度的FutureTask对象

FutureTask futureTask2 =newFutureTask(callable2);

ExecutorService executor =Executors.newFixedThreadPool(2);// 创建线程池并返回ExecutorService实例

executor.execute(futureTask1);// 执行任务

executor.execute(futureTask2);

while(true){

try{

if(futureTask1.isDone()&& futureTask2.isDone()){// 两个任务都完成System.out.println(“Done”);

executor.shutdown();// 关闭线程池和服务

return;

}

if(!futureTask1.isDone()){// 任务1没有完成,会等待,直到任务完成 System.out.println(“FutureTask1 output=”+futureTask1.get());

}

System.out.println(“Waiting for FutureTask2 to complete”);

String s = futureTask2.get(200L,TimeUnit.MILLISECONDS);

if(s!=null){

System.out.println(“FutureTask2 output=”+s);

}

}catch(InterruptedException|ExecutionException e){

e.printStackTrace();

}catch(TimeoutException e){

//do nothing

}

} }}

运行如上程序后,可以看到一段时间内没有输出,因为get()方法等待任务执行完成然后才输出内容.输出结果如下:

FutureTask1 output=pool-1-thread-1WaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeWaitingforFutureTask2 to completeFutureTask2 output=pool-1-thread-2Done

下载实验06 线程应用及线程并发库word格式文档
下载实验06 线程应用及线程并发库.doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    操作系统-创建线程,利用互斥实现线程共享变量通信介绍

    2016-2017学年度第一学期大作业 课程名称: 操作系统(含课程设计) 任课教师:解晓萌作业题目: 创建线程,利用互斥实现线程共享变量通信姓名:鲁 斌学号: 20***02专业: 计算机科......

    黑马程序员C语言教程:深入浅出-服务器高并发库libevent5篇范文

    标题:深入浅出-服务器高并发库libevent(二) 上一章,我们简单介绍了libevent的环境的安装,和简单的事例。 现在先不要着急分析他的代码,在这里我首先要介绍一个专业名词“Reactor......

    实验五 电子商务及其应用

    广东海洋大学寸金学院学生实验报告书 实验名称 系 学生姓名 实验六 电子商务及其应用 课程名称 财务会计教育 会计电算化 班级学号 专业实验地点 实验楼303 实验日期 一、......

    多媒体技术及应用实验

    实验一、利用Photoshop制作个性化名片开发工具:Photoshop CS5 实验要求:利用合适的素材,再加上自己的创意设计,设计出漂亮的一款富有创意的学生本人的个性化名片。 实验报告:(1)打......

    实验6JavaAWT及Swing应用

    实验6 Java AWT及Swing应用 实验内容 (1)按钮有序排列 (2)密码验证问题 (3)名片录入管理界面设计 (4)文字字体设计窗体 1、按钮有序排列 实验目的: (1) 了解 GUI 的概念 ;......

    图的应用 实验(精选5篇)

    图的应用 实验日志 实验题目:图的建立及输出 实验目的:建立图的存储结构(图的类型可以是有向图、无向图、有向网、无向网,学生可以任选两种类型),能够输入图的顶点和边的信息,并存......

    实验二关于我国信用卡应用

    实验二:关于我国信用卡应用(2学时) 1.我国各家新兴的商业银行也都涉足银行卡领域,纷纷创建具有自身特色的银行卡品牌,建立了各自的银行网络系统工程。各家银行的竞争,丰富了银行卡......

    农业机械与应用实验教学大纲

    实验教学 实验一:农用柴油机的曲柄连杆机构拆装实验 掌握内燃机拆装的基本技术要求和技术要领,学会正确选用和使用常用工具。掌握内燃机的曲柄连杆机构、正时齿轮室的拆装。......