- 1.线程与进程区别?
- 2.多线程的作用?
- 3.多线程应用场景?
- 4.多线程创建方式?
- 5.spring @Async异步注解 结合线程池
- 6.什么是守护线程?
- 7.多线程有几种运行状态?
- 8.join()方法作用?
- 9.什么是线程安全问题?
- 10.多线程如何解决线程安全问题/ 多线程如何实现同步呢?
- 11.同步函数和静态同步函数使用的是什么锁?
- 12.什么是死锁?
- 13.多线程三大特性?
- 14.什么是Java内存模型?
- 15.Volatile关键字是什么作用?
- 16.volatile与synchronized区别?
- 17.ThreadLocal作用是什么?
- 18.wait()、notify、notifyAll()方法作用分别是?
- 19.wait与sleep区别?
- 20.Lock 接口与 synchronized 关键字的区别?
- 21.为什么拥有了synchronized关键字还要出现lock锁?
- 22.Condition用法?
- 23.如何停止线程?
- 24.如何使用interrupt停止线程?
- 25.Vector与ArrayList区别?
- 26.三种线程安全的List
- 27.HasTable与HasMap的区别?
- 28.synchronizedMap和synchronizedList作用分别是?
- 29.ConcurrentHashMap作用和原理?
- 30.CountDownLatch和CyclicBarrier的区别?
- 31.Semaphore的作用?
- 32.线程池的作用?
- 33.线程池有哪些类型?
- 34.什么是悲观锁?什么是乐观锁?
- 35.CAS无锁机制是什么?
- 36.什么是多线程的ABA问题?
- 37.乐观锁的原理?
- 38.在实际开发中如何去避免ABA问题?
- 39.什么是重入锁?
- 40.什么是自旋锁?
1.线程与进程区别?
进程是所有线程的集合,每一个线程是进程中的一条执行路径。
进程包括线程
2.多线程的作用?
提高程序执行效率
3.多线程应用场景?
异步写入日志(日志框架的底层),多线程下载,分批发送短信,分批发送邮件
4.多线程创建方式?
1).继承Thread类
2).实现Runnable接口
3).使用Callable和Future创建线程
//使用callable的方式创建线程(可以抛出异常,可以返回值)
FutureTask
@Override
public Integer call() throws Exception {
int a=1;
int b=1;
return a+b;
}
});
new Thread(integerFutureTask).start();
Integer integer = integerFutureTask.get();
System.out.println(integer);
可用于分段计算
4).使用线程池例如用Executor框架
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + “>我是子线程<”);
}
});
5.spring @Async异步注解 结合线程池
@Async注解使用条件:
@Async注解一般用在类的方法上,如果用在类上,那么这个类所有的方法都是异步执行的;
所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象;
调用异步方法类上需要配置上注解@EnableAsync
使用方式:在启动类或者要调用异步方法的类加上@EnableAsync注解,然后在被调用的方法上加上@Async注解
注意:如出现循环依赖的问题,可以使用set注入或者加上@Lazy懒加载注解
6.什么是守护线程?
主线程挂了,守护线程也会被自动销毁.
7.多线程有几种运行状态?
新建状态、就绪状态、运行状态、阻塞状态及死亡状态
新建状态:新建线程对象
就绪状态:执行start返回后,但是未执行run方法时
运行状态:获得cpu时间片,执行run方法时
阻塞状态:
sleep方法导致
io阻塞
死锁导致
死亡状态:
run方法正常退出而自然死亡
一个未捕获的异常终止了run方法
8.join()方法作用?
让其他线程变为等待,使该线程优先执行
9.什么是线程安全问题?
当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题。
例如: //开100个线程模拟100个人进行抢票操作
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 20; j++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
a—;
System.out.println(a);
}
}).start();
}
注意:a++或者a—都是线程不安全的代码块,非原子性,需要加synchronized代码块
10.多线程如何解决线程安全问题/ 多线程如何实现同步呢?
1).同步代码块
synchronized(同一个数据){
可能会发生线程冲突问题
}
2).同步函数
public synchronized void method() {}
3).静态同步函数
public static synchronized void method() {}
11.同步函数和静态同步函数使用的是什么锁?
同步函数使用的是this锁,静态同步函数使用的是该函数所在类的字节码文件对象,类名.class
12.什么是死锁?
同步中嵌套同步,导致锁无法释放
13.多线程三大特性?
原子性,有序性,可见性
可见性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。
可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
有序性:一般来说处理器为了提高程序运行效率,可能会对输入代码进行优化,
它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,
但是它会保证程序最终执行结果和代码顺序执行的结果是一致的
14.什么是Java内存模型?
定义了一个线程对另一个线程可见。共享变量存放在主内存中,
每个线程都有自己的本地内存,当多个线程同时访问一个数据的时候,
可能本地内存没有及时刷新到主内存,所以就会发生线程安全问题。
15.Volatile关键字是什么作用?
Volatile 关键字的作用是变量在多个线程之间可见。但是不能保证原子性
16.volatile与synchronized区别?
仅靠volatile不能保证线程的安全性。(原子性)
①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法
②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。
synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。
多个线程争抢synchronized锁对象时,会出现阻塞。
17.ThreadLocal作用是什么?
一个线程内部的存储类,可以指定线程内部存储数据
多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,
为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。
ThreadLocal是除了加锁这种同步方式之外的一种保证一种规避多线程访问出现线程不安全的方法,
当我们在创建一个变量后,
如果每个线程对其进行访问的时候访问的都是线程自己的变量这样就不会存在线程不安全问题。
原理:使用map集合存储相关线程私有数据,使用线程id作为key
18.wait()、notify、notifyAll()方法作用分别是?
三个方法都是属于Object的方法
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
19.wait与sleep区别?
sleep属于Thread类,wait属于Object类
sleep指定了线程暂停执行的时间
sleep不释放锁,wait释放锁
20.Lock 接口与 synchronized 关键字的区别?
lock需要手动释放锁,synchronized会自动释放锁
Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
lock锁可以判断是否获取锁,并且可以中断锁;synchronized无法中断,要是无法获取锁会一直阻塞。
21.为什么拥有了synchronized关键字还要出现lock锁?
synchronized的缺陷:
1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
2)线程执行发生异常,此时JVM会让线程自动释放锁。
那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。
因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。
22.Condition用法?
Condition的功能类似于在传统的线程技术中的,Object.wait()和Object.notify()的功能。
Condition是lock锁的线程通讯
23.如何停止线程?
1.正常停止,执行完run方法之后
2.使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
3.使用interrupt方法中断线程。
24.如何使用interrupt停止线程?
相关方法:
interrupt():其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。
interrupted():内部实现是调用的当前线程的isInterrupted(),并且会重置当前线程的中断状态(即变回false)
isInterrupted():是调用该方法的对象所表示的那个线程的isInterrupted(),不会重置当前线程的中断状态
开始是false,后面可以手动调用interrupt()方法设置为true
25.Vector与ArrayList区别?
Vector线程安全、ArrayList线程不安全
之所以是线程安全,是因为add方法加了synchronized关键字
26.三种线程安全的List
1.获取线程安全的List我们可以通过Vector、Collections.synchronizedList()方法和CopyOnWriteArrayList三种方式
2.读多写少的情况下,推荐使用CopyOnWriteArrayList方式
3.读少写多的情况下,推荐使用Collections.synchronizedList()的方式
大概原理:
Vector使用方案级别synchronized锁
Collections的静态方法synchronizedList(List< T> list),基本原理使用synchronized代码块,并且读写都会加锁
CopyOnWriteArrayList,使用lock锁
27.HasTable与HasMap的区别?
HashMap不是线程安全的,HasTable是线程安全的
源码分析:
HashTable:
put方法加了synchronized关键字,导致写入很慢,并发容易阻塞
get方法也加了synchronized关键字,导致读取很慢,并发容易阻塞
HashTable不建议使用,读写都加了悲观锁。
HashMap:
put方法没有加synchronized,线程不安全,效率高
get方法没有加synchronized,线程不安全,效率高
28.synchronizedMap和synchronizedList作用分别是?
Collections.synchronizedMap(m) 将线程不安全Map集合变为线程安全Map集合
Collections.synchronizedList(m) 将线程不安全List集合变为线程安全List集合
29.ConcurrentHashMap作用和原理?
ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个
小的HashTable,它们都有自己的只要多个修改操作发生在不同的段上,它们就可以并
发进行。
把一个整体分成了16个段(Segment.也就是最高支持16个线程的并发修改操作。
这也是在重线程场景时减小锁的粒度从而降低锁竞争的一种方案。并且代码中大多共享变
30.CountDownLatch和CyclicBarrier的区别?
countDownLatch:是一个计数器,线程完成一个记录一个,计数器递减,只能只用一次,计数器为0,则线程等待失效。存在减一方法
CyclicBarrier:的计数器更像一个阀门,需要所有线程都到达,然后继续执行,计数器递增,
提供reset功能,可以多次使用。没有减一方法,线程数达到数量的时候,await方法就会放行。
31.Semaphore的作用?
Semaphore 是 synchronized 的加强版,作用是控制线程的并发数量,就这一点而言,单纯的synchronized 关键字是实现不了的。
只能控制一定数量的线程进入该代码块
32.线程池的作用?
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性,线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。
但是,要做到合理利用线程池,必须对其实现原理了如指掌。
线程池是为突然大量爆发的线程设计的,通过有限的几个固定线程为大量的操作服务,减少了创建和销毁线程所需的时间,从而提高效率。
如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),况且我们还不能控制线程池中线程的开始、挂起、和中止。
33.线程池有哪些类型?
newCachedThreadPool 可缓存的线程池,线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
newScheduledThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列
newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
34.什么是悲观锁?什么是乐观锁?
悲观锁:悲观锁悲观的认为每一次操作都会造成更新丢失问题,在每次查询时加上排他锁。
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
例如:Select * from xxx for update;
乐观锁:乐观锁会乐观的认为每次查询都不会造成更新丢失,利用版本字段控制
比如git版本控制,java原子类
35.CAS无锁机制是什么?
CAS 即比较并替换,实现并发算法时常用到的一种技术。
CAS操作包含三个操作数——内存位置、预期原值及新值。
执行CAS操作的时候,将内存位置的值与预期原值比较,
如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作
cas(V , Expected , NewValue)
V现在的实际值,Expected现在的期望值(假设没有别的线程修改),需要修改成的值
如果A==Expected则进行修改,否则不进行修改,锁自旋
36.什么是多线程的ABA问题?
ABA问题的根本在于cas在修改变量的时候,无法记录变量的状态,比如修改的次数,否修改过这个变量。
这样就很容易在一个线程将A修改成B时,另一个线程又会把B修改成A,造成casd多次执行的问题。
37.乐观锁的原理?
CAS无锁机制+版本机制
一个值a,A线程和B线程去修改,
A线程和B线程同时获取a的版本号和a的值,
A和B线程不论哪个先执行完,
后执行的都要去对比版本号,版本号肯定不一致,
所以线程是安全的。
如果没有对比版本号:
A和B获取a的值,如果A先执行,
那么B后执行会把A修改的值覆盖,
理论上应该是B在A的基础上修改。
38.在实际开发中如何去避免ABA问题?
AtomicStampedReference
AtomicStampedReference
构造方法参数分别是值和版本号,每次修改都可以使版本号修改。
注意:普通的原子类不能避免ABA问题
39.什么是重入锁?
重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。
在JAVA环境下 ReentrantLock 和synchronized 都是可重入锁
40.什么是自旋锁?
自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区。
终结…….狗头!