1.FutureTask类有什么作用?它实现了哪些接?Callable接口和Runnable接口有什么不同?
作用:
1)是runnable的实现
2)它的构造参数接受callable
3)并且有泛型定义,记录任务的执行结果
4)get方法可以获取callable任务的执行结果,如果任务执行完直接返回结果,任务还没执行完,调用线程会阻塞线程直至get返回结果
不同:
1)callable可以携带返回值,泛型
2)callable可以抛出异常
3)callable的方法名是call,runnable方法名是run
2.请查阅JDK自学线程池的相关类,如ThreadPoolExecutor构造器各个参数的意义, 利用线程池编写多线程程序。
1)corePoolSize。核心线程池大小。这个参数是否生效取决于allowCoreThreadTimeOut变量的值,该变量默认是false,即对于核心线程没有超时限制,所以这种情况下,corePoolSize参数是起效的。如果allowCoreThreadTimeOut为true,那么核心线程允许超时,并且超时时间就是keepAliveTime参数和unit共同决定的值,这种情况下,如果线程池长时间空闲的话最终存活的线程会变为0,也即corePoolSize参数失效。
2) maximumPoolSize。线程池中最大的存活线程数。这个参数比较好理解,对于超出corePoolSize部分的线程,无论allowCoreThreadTimeOut变量的值是true还是false,都会超时,超时时间由keepAliveTime和unit两个参数算出。
3)keepAliveTime。超时时间。
4)unit。超时时间的单位,秒,毫秒,微秒,纳秒等,与keepAliveTime参数共同决定超时时间。
5) workQueue。当调用execute方法时,如果线程池中没有空闲的可用线程,那么就会把这个Runnable对象放到该队列中。这个参数必须是一个实现BlockingQueue接口的阻塞队列,因为要保证线程安全。有一个要注意的点是,只有在调用execute方法是,才会向这个队列中添加任务,那么对于submit方法呢,难道submit方法提交任务时如果没有可用的线程就直接扔掉吗?当然不是,看一下AbstractExecutorService类中submit方法实现,其实submit方法只是把传进来的Runnable对象或Callable对象包装成一个新的Runnable对象,然后调用execute方法,并将包装后的FutureTask对象作为一个Future引用返回给调用者。Future的阻塞特性实际是在FutureTask中实现的,具体怎么实现感兴趣的话可以看一下FutureTask的源码。
6) threadFactory。线程工厂类。用于在需要的时候生成新的线程。默认实现是Executors.defaultThreadFactory(),即new 一个Thread对象,并设置线程名称,daemon等属性。
7)handler。这个参数的作用是当提交任务时既没有空闲线程,任务队列也满了,这时候就会调用handler的rejectedExecution方法。默认的实现是抛出一个RejectedExecutionException异常。
3.volatile关键字有什么作用?
1)多线程之间可见性。
2)禁止指令重排序。
4.Java提供了哪些同步机制来实现互斥?
1)对象监视器(monitor)与synchronized
Synchronized的三种用法:
synchronized 代码块:监视器就是指定的对象。
synchronized 方法:监视器就是this对象。
synchronized 静态方法:监视器就是相应的Class对象。
2)Java并发包中的锁类
接口
ReentrantLock类
5.编写Java程序模拟烧水泡茶最优工序。
6.请使用Java并发包的Lock及Conditon改写例9.11。
存钱
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();}
}
7. 编写一个多线程Java应用模拟生产者/消费者模型,各产生10个生产者和消费者线程,共享一个缓冲区队列(长度自设),生产者线程将产品放入到缓冲区,消费者线程从缓冲区取出产品。
8.阅读公众号“码农翻身”的文章---《我是一个线程》。