1.FutureTask类有什么作用?它实现了哪些接口?
Callable接口和Runnable接口有什么不同?
在Java中,一般是通过继承Thread类或者实现Runnable接口来创建多线程, Runnable接口不能返回结果,如果要获取子线程的执行结果,一般都是在子线程执行结束之后,通过Handler将结果返回到调用线程,jdk1.5之后,Java提供了Callable接口来封装子任务,Callable接口可以获取返回结果。
Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛
2.请查阅JDK自学线程池的相关类,如ThreadPoolExecutor构造器各个参数的意义, 利用线程池编写多线程程序。
-
corePoolSize。核心线程池大小。这个参数是否生效取决于allowCoreThreadTimeOut变量的值,该变量默认是false,即对于核心线程没有超时限制,所以这种情况下,corePoolSize参数是起效的。如果allowCoreThreadTimeOut为true,那么核心线程允许超时,并且超时时间就是keepAliveTime参数和unit共同决定的值,这种情况下,如果线程池长时间空闲的话最终存活的线程会变为0,也即corePoolSize参数失效。
-
maximumPoolSize。线程池中最大的存活线程数。这个参数比较好理解,对于超出corePoolSize部分的线程,无论allowCoreThreadTimeOut变量的值是true还是false,都会超时,超时时间由keepAliveTime和unit两个参数算出。
-
keepAliveTime。超时时间。
-
unit。超时时间的单位,秒,毫秒,微秒,纳秒等,与keepAliveTime参数共同决定超时时间。
-
workQueue。当调用execute方法时,如果线程池中没有空闲的可用线程,那么就会把这个Runnable对象放到该队列中。这个参数必须是一个实现BlockingQueue接口的阻塞队列,因为要保证线程安全。有一个要注意的点是,只有在调用execute方法是,才会向这个队列中添加任务,那么对于submit方法呢,难道submit方法提交任务时如果没有可用的线程就直接扔掉吗?当然不是,看一下AbstractExecutorService类中submit方法实现,其实submit方法只是把传进来的Runnable对象或Callable对象包装成一个新的Runnable对象,然后调用execute方法,并将包装后的FutureTask对象作为一个Future引用返回给调用者。Future的阻塞特性实际是在FutureTask中实现的,具体怎么实现感兴趣的话可以看一下FutureTask的源码。
-
threadFactory。线程工厂类。用于在需要的时候生成新的线程。默认实现是Executors.defaultThreadFactory(),即new 一个Thread对象,并设置线程名称,daemon等属性。
-
handler。这个参数的作用是当提交任务时既没有空闲线程,任务队列也满了,这时候就会调用handler的rejectedExecution方法。默认的实现是抛出一个RejectedExecutionException异常。
3.volatile关键字有什么作用?
在JVM1.2之前,Java总是从主存读取变量,但随着JVM的优化,线程可以把主存变量保存在寄存器(工作内存)中操作,线程结束再与主存变量进行同步,然而,当线程没有执行结束就发生了互换这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还在继续使用它在寄存器中变量值的副本,造成数据的不一致。要解决这个问题,就需要把该变量声明为volatile(不稳定的),它指示JVM这个变量是不稳定的,每次使用它都到主存进行读取。
4.Java提供了哪些同步机制来实现互斥?
使用synchronized来给共享区域加锁,确保共享资源安全。
如果一个线程调用了某个对象的synchronized方法,它在这个方法运行完之前不会被别的线程打断,这就是线程的同步机制。一般将共享资源放在这个同步方法内部,这样就保证在一个线程对这个资源操作完之后别的线程才可以访问。
5.编写Java程序模拟烧水泡茶最优工序。
import java.util.Date;
public class Tea implements Runnable{
static Date date = new Date();
public static void main(String[] args) throws Exception{
HeatUpWater h1 = new HeatUpWater();
WashCup w1 = new WashCup();
Tea m1 = new Tea();
Thread t1 = new Thread(h1);
Thread t2 = new Thread(w1);
Thread t3 = new Thread(m1);
try{
t1.start();
t2.start();
t2.join();
t1.join();
}catch (Exception e){
System.out.println("Error!");
}
t3.start();
}
public void run(){
System.out.println(date+" 正在泡茶");
try{
Thread.sleep(1000);
}catch (Exception e){
}
}
}
class HeatUpWater implements Runnable{
static Date date = new Date();
public void run(){
int time = 10;
while(time != 0){
System.out.println(date+" 正在烧水");
time--;
try{
Thread.sleep(1000);
}catch (Exception e){
System.out.println("Heat up water is in the Error!");
}
}
}
}
class WashCup implements Runnable{
static Date date = new Date();
public void run(){
int time = 5;
while(time != 0){
System.out.println(date+" 正在洗茶杯");
time--;
try{
Thread.sleep(1000);
}catch (Exception e){
}
}
}
}
6.请使用Java并发包的Lock及Conditon改写例9.11。
import java.util.concurrent.locks.*;
class Account{
volatile private int value;
volatile private boolean isMoney = false;
private final ReentrantLock lock = new ReentrantLock();
private Condition SaveCondition = lock.newCondition();
private Condition FetchCondition = lock.newCondition();
}
void put(int i) {
lock.lock();
try{
while(isMoney){
try{
SaveCondition.await();
} catch(Exception e){}
}
value = value + i;
System.out.println("存入"+i+" 账上金额为:"+value);
isMoney = true;
FetchCondition.signal();
} finally {
lock.unlock();
}
}
int get(int i) {
lock.lock();
try{
while(!isMoney ){
try {
FetchCondition.await();
} catch(Exception e){}
}
if (value>i)
value = value - i;
else {
i = value;
value = 0; }
System.out.println("取走"+i+" 账上金额为:"+value);
isMoney = false;
SaveCondition.signal();
return i;
} finally {
lock.unlock();}
}