JavaSE-多线程

一、进程
1.进程:操作系统(OS)中,每一个被执行的应用程序。
2.注意:目前操作系统支持多进程,并发执行的任务。
3.多进程并发执行的原理:微观上串行(一个一个的进程进行执行,获取cpu时间片的进程具有执行权);宏观上并行(所有的进程看似一起执行)
二、线程
1.概念:在一个进程中,并发执行的多个任务。线程是进程执行任务的单元、单位。线程也被称为轻量级的进程。
2.主线程:目前程序为单线程,此线程以main函数的开始为开始,以main函数的结束为结束,此线程被称为主线程(主线程默认执行main函数)
3.线程的组成部分:
(1) cpu:获取到cpu时间片的线程获取执行权
(2) 数据:栈空间独立(每一个线程有独立的栈空间);堆空间共享(多个线程可以操作同一个堆空间)。栈空间用于存储局部变量;堆空间用于存储对象。
(3) 程序代码
4.代码实现多线程
(1) 第一种方式:
a. 类继承 java.lang.Thread 类,覆盖 run方法
b. 创建线程对象:MyThread t1 = new MyThread();
c. 开启线程:t1.start() ; // JVM默认执行 run方法
(2) 第二种方式:
a. 类实现 java.lang.Runnable接口,同时实现run方法
b. 创建线程的目标对象:Mytarget mt = new MyTarget();
c. 创建线程对象: Thread t2 = new Thread(mt); // 将目标对象作为参数进行传递
d. 开启线程:t2.start(); // JVM默认调用run方法
三、线程的状态
1.static void sleep(long ms):让当前线程处于休眠状态,休眠的单位是毫秒(ms),处于休眠状态的线程进入有限期等待状态 。sleep方法会让当前线程释放cpu,但是不释放锁标记。
2.void join() : 让某 线程加入到自身任务中,在哪个线程中调用其他线程join方法,则代表此线程让步其他线程优先执行,此线程从而进入无限期的等待状态。
例如:在主线程中main函数中: t.join() ; 代表主线程让步于t线程执行
四、线程同步
1.临界资源:多线程并发时,被多个线程共享的同一个对象,称为临界资源。
2.原子操作:不可以分割的多步操作,被视为一个整体,其执行顺序和步骤不能被打破。
3.线程同步:多线程并发访问时,为了保证临界资源的正确性,从而不破坏操作中的原子操作。(保护原子操作不能被破坏)
4.线程同步的两种方式:
(1) 同步代码块:对临界资源对象进行加锁。
a. 定义位置:方法内部
b. 利用 synchronized 对临界资源加锁
c. 语法: synchronized(临界资源对象){
// 原子操作
}
d. 执行的原理:当线程获取临界资源的锁标记时,锁标记空闲,则能获取该对象的锁标记,获取锁标记之后,可以执行同步代码块{}中的代码,而且只有当{}中所有的内容全部执行完,才释放拥有的锁标记;但是当线程获取临界资源对象的锁标记时,锁标记被其他线程占用,则此线程进入阻塞状态(Blocked状态),只有当其他线程释放锁标记,此线程获取锁标记,才结束阻塞状态,同时获取cpu,可以执行{}中 的内容。
(2) 同步方法:
a. 用 synchronized修饰 方法:被 synchronized修饰的方法称为同步方法
b. 语法:
修饰符 synchronized 返回值类型 方法名(形参列表)throws 异常{
// 原子操作
}
c. 同步方法等价于 同步代码块:是对当前对象进行加锁
synchronized(this){
// 原子操作
}
五、线程间的通信
1.java.lang.Object类中提供了用于线程间通信的方法:等待wait与通知notify
2.等待:wait() :
(1) wait方法的调用,需要使用在该对象的同步代码块中
(2) 如果一个线程调用了 wait方法,此线程进入等待状态,wait() -->进入无限期等待状态
(3) wait方法会当前线程释放锁标记,同时释放cpu
3.通知:
(1) notify():通知一个线程从等待状态结束
(2) notifyAll(): 通知所有的线程从等待结束
注意:notify()/notifyAll的应用需要使用在该对象的同步代码块中;
notify()/notifyAll:只是起到通知的作用,不释放该线程拥有的锁标记。
面试题目:写出 sleep(long ms)方法 和 wait() 方法区别?
解 析:sleep(long ms):让线程进入休眠状态(有限期等待状态),同时释放 cpu,但是不释放锁标记
wait()方法:让当前线程进入无限期等待状态,释放cpu同时也释放锁标记。
面试题目:写出 ArrayList 和 Vector的区别?
解析: ArrayList:线程不安全,方法为非同步方法,运行效率较高。
Vector:线程安全,方法为同步方法,不同线程需要等待锁标记,效率相对较低。
面试题目:HashMap 和 Hashtable的区别?
解析: Hashtable:线程安全,方法为同步方法,运行效率相对较低。
HashMap :线程不安全,方法为非同步方法,运行效率相对较高。
六、线程池
1.线程池:线程容器,预先创建一些线程存储在池中,线程池中线程可以被重复的使用。
2.线程池的好处:减少创建线程和销毁线程的次数,反复使用池的线程,从而提高效率。
3.常用的线程池对应接口和类:(位于 java.util.concurrent 包中)
(1) Executor : 线程池根接口、顶级接口。
(2) ExecutorService : 是 Executor的子接口,是线程池常用接口。
a. submit(Runnable r):将 Runnable类型的任务提交给线程池。
b. submit(Callable< V > c) :将Callable类型的任务提交给线程池。
c. shutdown():将线程池关闭,从而线程池自动销毁所有线程对象。
(3) Executors:线程池对应工具类(工厂类:提供线程池对象的类),内容提供大量静态方法,用于获取线程池对象:
a. static ExecutorService newFixedThreadPool(int n) :创建一个可重复固定个数线程的线程池对象,参数代表线程的数量。
b. static ExecutorService newCachedThreadPool():创建一个线程个数为动态的线程池对象,线程池的线程个数没有上限。
七、Callable接口(位于java.util.concurrent包)
1.JDK5.0之后提出一个Callable接口,应用类似于 Runnable接口,代表一个线程任务。
2.Callable接口带有泛型,常用的方法为:
V call():带有泛型类型的返回值,可以抛出任意类型异常。
3.方法的调用:
(1) 同步调用:调用者一旦发生方法的调用,则调用者需要停下,被调用的方法方法先执行,被调用的方法执行完毕之后,返回到调用位置,则调用者才能继续往下执行。
(2) 异步调用:调用者一旦发生方法的调用,调用者立即可以执行自身后续的内容。
4.Future的应用:
(1) Future接口可以接收异步计算结果,例如:pool.submit©; 对于 Callable任务的结果处理
(2) Future中常用的方法:
V get():从Future中获取结果。
八、常用的集合补充
1.CopyOnWriteArrayList(高效并且线程安全的集合类)
(1) 位于:java.util.concurrent 包中
(2) CopyOnWriteArrayList:在所有读操作(get/size方法:不会改变集合中数据内容操作)中不加锁;在写操作时加锁,为了保证数据正确性,写操作时,拷贝一个副文本,在副文本上进行写操作,写操作完成之后,新的数据替换旧的数据。允许多个线程同时进行读操作,但是同一时间只允许一个线程进行写操作,同时一个线程进行写操作,也允许多个线程进行读操作。(牺牲写操作的效率提高读操作的效率)
(3) 应用场景:读操作的次数远远大于写操作次数
(4) CopyOnWriteArrayList和 Vector的区别。
解析:CopyOnWriteArrayList在读次数远远多于写操作时,效率远高于Vector;但线程都是安全
CopyOnWriteArrayList和Arraylist的区别。
解析:CopyOnWriteArrayList在读次数远远多于写操作时,效率仅次于ArrayList;CopyOnWriteArrayList线程安全;ArrayList线程不安全
(5) CopyOnWriteArrayList 用法和 ArrayList一样(遍历方式等)
2.ConcurrentHashMap:(高效并且线程安全的集合类)
(1) 位于 java.util.concurrent包中
(2) ConcurrentHashMap采用的分段锁,减小锁的范围,从而减少锁冲突可能性,提高线程的并发效率。(分为16段)
(3) 应用场景:在全局操作不频繁的情况下(例如size等操作),效率较高
注意:jdk8.0版本及以上ConcurrentHashMap采用CAS算法(比较交换算法)和synchronized保证线程安全。
(4) ConcurrentHashMap 、HashMap、Hashtable的区别。
ConcurrentHashMap :线程安全,执行效率更高,采用的分段锁提高并发效率。全局操作不频繁时,效率仅次于HashMap
HashMap:线程不安全,运行效率高
Hashtable:线程安全,底层锁粒度太大,所以执行小较低。
3.Queue接口(java.util包中)
(1) Queue是Collection的子接口,描述队列存储结构,队列存储结构的点:先进先出,后进后出,队列存储结构简称为FIFO
(2) 常见的方法:
offer(Object o):往队列中添加元素
poll():获取队头元素,并移除队头元素。
4.BlockingQueue:是 Queue的子接口(java.util.concurrent包中)
(1) 常用的方法:
put(Object o):往队列结构中存储元素,如果没可用空间,则等待
take():从队列结构中取元素,没有可取元素,则等待
(2) 常用实现类:
ArrayBlockingQueue:数组实现,指定固定容量,有界队列
LinkedBlockingQueue:链表实现,可以实现无界队列
5.ConcurrentLinkedQueue是 Queue接口的实现类
(1) java.util.concurrent
(2) 特点:无锁并且线程安全的集合实现类,采用的CAS(比较交换算法)实现线程安全。

你可能感兴趣的:(队列,多线程,java,面试)