JAVA多线程
任务(线程的执行体)、创建和运行线程
定义任务:
- 继承Thread类 (将任务和线程合并在一起)
- 实现Runnable接口 (将任务和线程分开)
- 实现Callable接口 (利用FutureTask执行任务)
//定义线程
class T extends Thread{ //extends继承父类
@Override
public void run(){
}
}
class R implements Runnable{ //implements为实现接口,必须在类内重写才能使用方法
@Override
public void run(){
}
}
class C implements Callable<Sting>{
@Override
public String call() throws Exception{
return ;
}
}
//启动
new T().start();
new Thread(new R()).start(); //R的实例作为Thread的target创建Thread对象
FutureTask<String> target = new FututreTask<>(new C()); //结合FutureTask可获取线程执行结果
new Thread(target).start();
log.info(target.get());
- 实现Runnable接口比继承Thread类所具有的优势:
- 适合多个相同的程序代码的线程去处理同一个资源
- 可以避免java中的单继承的限制
- 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
- 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
- Callable和Future的优势: 可以在任务执行完毕之后得到任务执行结果, 而Runnable和Thread必须通过共享变量或者使用线程通信的方式获取执行结果
Future接口
Future接口表示异步任务,是还没有完成的任务给出的未来结果.
Callable用于产生结果,Future用于获取结果。
Future三种功能:
- 能够取消任务。 cancel()
- 判断任务是否完成。 isDone()
- 能够获取任务执行结果。 get()
线程池
线程池是一种管理线程的工具。预先创建一些线程,任务提交时直接执行.
既可以节约创建线程的时间,又可以控制线程的数量。
ExecutorService接口(继承Executor接口)
//创建
ExecutorService es = Executors.newFixedThreadPool(int); //定长,可控制最大并发数,超出等待
newCachedThreadPool(int); //超出可灵活回收空线程,若无可回收则新建
newScheduledThreadPool(); //定长线程,支持定时及周期性任务执行
newSingleThreadExecutor(); //单线程化,保证任务按照顺序(FIFO,LIFO,优先级)执行
//运行
es.execute(Runnable); //不能获得任务执行结果
es.submit(Runnable); //返回Future对象 future.get()可检查任务完成
es.submit(Callable); //返回future对象并且call()有返回值
es.invokeAny(); //传入callable集合
es.invokeAll();
//关闭
es.shutdown();
案例-多文件词频统计
ArrayList类 (实现List接口)
动态数组
ArrayList arr = new ArrayList(); //参数可以为数组或数值或者为空
arr.add(int index, Object obj); //添加元素
arr.remove(); //根据对象或者下标
arr.size();
arr.set(int index, Object obj); //替换元素
arr.clear();
arr.get(int index); //查找元素
Hashmap (实现Map接口)
HashMap<Integer, String> mapper = new HashMap<Integer,String>();
mapper.put(1, "hello"); //添加元素 重复put会替换旧值
mapper.get(key); //获取元素
mapper.getOrDefault(Object key, V defaultValue); //获取key对应value,找不到key则返回默认值
mapper.remove(key); //删除元素
mapper.containsKey(); //检查是否存在key映射 返回布尔
mapper.keySet(); //返回key集合
mapper.entrySet(); //返回包含所有映射关系的Map.Entry类型的Set集合
Map.Entry
Map是java中的接口,Map.Entry是Map的一个内部接口。此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)接口有getKey(), getValue()方法
//map不能直接使用迭代器因为map没有像set继承
//map.entry对map遍历
//方法一
Map map = new HashMap();
Irerator iterator = map.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry entry = iterator.next();
Object key = entry.getKey(); //获得键值对的键
}
//方法二 for-each循环
for(Map.Entry<Integer, Integer> entry : mapper.entrySet()) {
entry.getValue(); //获得键值对的值
}
//方法三 遍历key集合(这里假设键是string)
for(String key: mapper.keySet()){
}
Java的Mapreduce实现
Main Hadoop classes: Configuration, Job, Mapper, Reducer, Combiner
Job job= Job.getInstance(conf, "")
'''Mapper'''
map(WritableComparable, Writable, Context)
context.write(K, V)
'''Reducer'''
reduce(WritableComparable, Iterator<Writable>, Context)
context.write(K, V)
Linux环境运行:
#编译
javac WordCount.java
jar cf wc.jar WordCount*.class
#运行
hadoop jar wc.jar WordCount input output
操作系统 进程线程模型
进程:
基本属性:进程是一个可拥有资源的独立单位,又是一个可以独立调度和分派的基本单位。
- 创建进程:必须为其分配所有资源(除CPU外),包括内存空间、I/O设备以及建立相应的数据结构PCB。
- 撤销进程:必须先对这些资源进行回收操作,然后在撤销PCB。
- 进程切换:由于要保留当前进程的CPU环境和设置新选中进程的CPU环境,为此需要花费不少的CPU时间。
进程是一个资源拥有者,因而在进程的创建、撤销和切换中,系统必须为之付出较大的时空开销。
创建背景:如果将作为调度和分派的经本单位不同时作为独立分配资源的单位,以使轻快运行;而对拥有资源的基本单位,又不频繁地对之进行切换。
线程:
线程是进程中的一个实体,是CPU调度和分派的基本单位。
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。
线程也同样有三种就绪、等待和运行基本状态。
线程的属性
- 每一个线程有一个唯一的标识符和一张线程描述表,记录了线程执行的寄存器和栈等现场状态。
- 不同的县城可以执行相同的程序,同一个服务程序被不同用户调用时操作系统为它创建不同的线程。
- 同一个进程中的各个线程共享进程的内存地址空间。
- 线程是处理器的独立调度单位,多个线程是可以并发执行的,在单个CPU的计算机系统中,各个线程可交替的占用CPU;在多个CPU计算机系统中,各个线程可同时占用不同的CPU,若各个CPU同时为一个进程内的各种线程服务是可以缩短进程的处理时间。
- 一个线程被创建后便开始了它的生命周期,直至终止,县城在生命周期内会经历等待、就绪和运行等各种状态变化。
线程与进程的比较
线程具有许多传统进程所具有的特征,故又称为轻量级进程或者是进程元,把床听的进程称为重量级进程。
- 调度:在传统的操作系统中,拥有资源的基本单位和独立调度、分派的基本单位都是进程。而在引入县城的操作系统中,则把线程作为调度和分派的基本单位。同一进程中,线程切换不会引起进程切换;而在由一个进程中的线程切换到另一个进程中的线程时,将会引起进程切换。
- 并发性:在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行。很有效的使用系统资源和提高系统的吞吐量。
- 拥有资源:线程的自己不拥有系统资源,但它可以访问其隶属进程的资源,可供同一进程的其他所有线程共享。
- 系统开销:由于在创建或撤销进程时,系统都要为之分配或回收资源。因此,操作系统所付出的开销将显著地大于在创建或撤销线程时的开销。
参考:
https://blog.csdn.net/qq_35598736/article/details/108431422
Java多线程学习(吐血超详细总结)_Evankaka的专栏-CSDN博客_java多线程
Java多线程学习(一)- Java线程的生命周期与创建方式_江湖人称小程的博客-CSDN博客
java Map及Map.Entry详解_xjk201的博客-CSDN博客_java map.entry