线程
1)线程和进程有什么区别?
一个线程是一个独立的运行环境,是一个独立的程序或者应用。线程则是进程中的一个任务。
线程是进程的子集,一个进程可以有多个线程并发执行不同任务。
不同进程使用不同内存空间,所有线程共享同一个内存空间(别和栈内存混淆,每个线程有单独的栈内存用于存储本地数据)
2)Java中如何实现线程?
两种方式:继承Thread类或实现Runnable接口
3)Thread中 start()和run()方法有什么区别?
start方法会启动新线程。若调用run方法 就和普通函数一样
4)Runnable 和 Callable接口的不同
Callable是JDK1.5中新增加的方法。主要区别是 Callable 的 call() 方法可以返回值和抛出异常,而 Runnable 的 run() 方法没有这些功能。Callable 可以返回装载有计算结果的 Future 对象。
public interface Runnable {
public void run();
}
public interface Callable<V> {
V call() throws Exception;
}
1)Callable 接口下的方法是 call(),Runnable 接口的方法是 run()。
2)Callable 的任务执行后可返回值,而 Runnable 的任务是不能返回值的。
3)call() 方法可以抛出异常,run()方法不可以的。
4)运行 Callable 任务可以拿到一个 Future 对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。**通过 Future 对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。**
5)Thread类只支持Runnable,Callable可以使用ExecutorService
5)Future接口
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
1. cancel方法,取消对此任务的执行。若任务已经完成,已经取消,或者取消失败则调用此函数失败。
如果调用成功,任务尚未启动 则此任务将永远不运行;若已启动 根据参数确定是否应该以试图停止任务的方式来中断执行此任务的线程
2.isCancelled方法,如果在任务完成前将其取消,则返回true。若调用cancel返回true之后,对该方法的后续调用始终返回true
3.isDone方法,如果任务已经完成,则返回true。无论是正常终止、异常终止还是取消完成的都将返回true
4.get 等待计算完成,然后获取结果
Future 接口也不能用在线程中,FutureTask 实现了 Runnable 和 Future,所以兼顾两者优点,既可以在 Thread 中使用,又可以在 ExecutorService 中使用。
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "个人博客:sunfusheng.com";
}
};
FutureTask<String> task = new FutureTask<String>(callable);
Thread t = new Thread(task);
t.start(); // 启动线程
task.cancel(true); // 取消线程
多线程
1)多线程的优点
1. 提高了程序的执行效率,多线程同时执行
2. 提高了资源利用率,CPU、内存等
2)多线程的缺点
1. 占用一定的内存空间
2. 线程越多CPU的调度开销越大
3. 程序的复杂度会上升
3)常用的多线程技术
synchronized wait/notify sleep volatile ThreadLocal join yield
4)join和synchronized的区别
join在内部使用wait方法进行等待,synchronized使用“对象监视器”完成同步
5)join和sleep的区别
join在内部是使用wait方法,所以具有释放锁的特点
线程池
1)线程池的优点
1. 避免线程的创建和销毁带来的性能开销(少开销)
2. 避免大量的线程间因互相抢占系统资源而阻塞的现象(避免阻塞)
3. 能对线程进行简单的管理并提供定时执行、间隔执行等功能(便于管理)
2)Java中使用线程池
Java里面线程池的顶级接口是 Executor,不过真正的线程池接口是 ExecutorService, ExecutorService 的默认实现是 ThreadPoolExecutor;普通类 Executors 里面调用的就是 ThreadPoolExecutor。
public interface Executor {
void execute(Runnable command);
}
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
...
}
public class Executors {
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
...
}
3)四种线程池
1)newCachedThreadPool 是一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute() 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。
2)newSingleThreadExecutor 创建是一个单线程池,也就是该线程池只有一个线程在工作,所有的任务是串行执行的,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
3)newFixedThreadPool 创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小,线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
4)newScheduledThreadPool 创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。
4)什么是 Executor 框架?
Executor框架在Java 5中被引入,Executor 框架是一个根据一组执行策略调用、调度、执行和控制的异步任务的框架。
无限制的创建线程会引起应用程序内存溢出,所以创建一个线程池是个更好的的解决方案,因为可以限制线程的数量并且可以回收再利用这些线程。利用 Executor 框架可以非常方便的创建一个线程池。
5)Executors 类是什么?
Executors为Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类提供了一些工具方法。Executors 可以用于方便的创建线程池。