1.FutureTask类的作用?实现了哪些接口?
future task类的作用:
可取消异步计算。此类提供了Future的基本实现,包括开始和取消计算的方法,查询计算是否完整,并检索计算结果。只有在计算完成后才能检索结果;如果计算尚未完成,get方法将阻止。计算完成后,计算将无法重新启动或取消(除非使用runAndReset()调用计算)。
FutureTask类实现了RunnableFuture接口,其中两个构造器:
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW;
}
2.Callable接口和Runnable接口有什么不同?
Callable接口的call()方法可以有返回值(通过Future接口的get()方法,不过此方法是阻塞性的),而Runnable接口的run()方法没有返回值
Callable接口的call()方法可以声明抛出异常,而Runnable接口的run()方法不可以声明抛出异常(run方法出现异常时会直接抛出,打印出堆栈信息,不过可以通过自定义ThreadFactory的方法来捕捉异常)
3.利用线程池编写多线程程序
package com.furtech.javautils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.LinkedBlockingQueue;
public class ThreadPool {
private static final Logger logger = LoggerFactory.getLogger(ThreadPool.class);
private final int poolSize;
private final LinkedBlockingQueue queue;
private final PoolWorker[] runable;
public ThreadPool(int poolSize) {
this.poolSize = poolSize;
queue = new LinkedBlockingQueue();
runable = new PoolWorker[poolSize];
for (int i = 0; i < poolSize; i++) {
runable[i] = new PoolWorker();
new Thread(runable[i], "pool-" + i).start();
}
}
public void execute(Runnable task) {
synchronized (queue) {
queue.add(task);
queue.notify();
}
}
private class PoolWorker implements Runnable {
@Override
public void run() {
Runnable task ;
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();
} catch (Exception e) {
logger.info("exception in queue waiting :{}",e.getMessage());
}
}
task = (Runnable) queue.poll();
}
try {
task.run();
} catch (RuntimeException e) {
logger.info("run exception : {}", e.getMessage());
}
}
}
}
}
class ThreadPoolMain {
public static void main(String[] args) {
ThreadPool pool = new ThreadPool(5);
int MaxSize = 100;
for (int i = 0; i < MaxSize; i++) {
pool.execute(() -> System.out.println(Thread.currentThread()));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4.volatile关键字的作用
1.保证可见性,不保证原子性
2.禁止指令重排
即为了线程对共享变量值的修改,能够及时的被其他线程看到。
但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错,所以并不能完全保证正确
class Resource implements Runnable {
volatile public int i;
public Resource(int _i){
i = _i;
}
public void run(){
while(true){
if (i>0){
try{
Thread.sleep(200);
}
catch(Exception e){}
i--;
System.out.println(Thread.
currentThread().getName()+" "+i);
}
else{
System.out.println(Thread.
currentThread().getName());
break;
}
}
}}
public class TestSecurity{
public static void main(String[] args){
Resource m = new Resource(9);
Thread t1 = new Thread(m);
Thread t2 = new Thread(m);
t1.start();
t2.start();
}
}
5.Java提供了哪些同步机制来实现互斥?
Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问,第一个是 JVM 实现的 synchronized,而另一个是 JDK 实现的 ReentrantLock。
synchronized:
1.同步一个代码块
它只作用于同一个对象,如果调用两个对象上的同步代码块,就不会进行同步。
public void func() {
synchronized (this) {
// ...
}
}
2.同步一个方法
它和同步代码块一样,作用于同一个对象。
public synchronized void func () {
// ...
}
3.同步一个类
作用于整个类,也就是说两个线程调用同一个类的不同对象上的这种同步语句,也会进行同步。
public void func() {
synchronized (SynchronizedExample.class) {
// ...
}
}
4.同步一个静态方法
作用于整个类。
public synchronized static void fun() {
// ...
}
ReentrantLock:
ReentrantLock 是 java.util.concurrent(J.U.C)包中的锁。