1.1 JUC是什么?
JUC 全称叫做:java.util.concurrent。是在并发编程中使用的工具类。
1.1.1 进程与线程
进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
线程:通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
在java中线程的状态有以下几种:
- NEW,(新建)
- RUNNABLE,(准备就绪)
- BLOCKED,(阻塞)
- WAITING,(不见不散)
- TIMED_WAITING,(过时不候)
- TERMINATED;(终结)
1.1.2 wait/sleep的区别
功能都是当前线程暂停,有什么区别?
wait:放开手去睡,放开手里的锁
sleep:握紧手去睡,醒了手里还有锁
1.1.3 并发与并行
并发:同一时刻多个线程在访问同一个资源,多个线程对一个点
并行:多项工作一起执行,之后再汇总
2.1 创建线程方式
大体上来说有三种:
- 集成Thread
- 实现Runnable接口
- 实现Callable(这个面试高频考点)
2.1.1 代码实现
额。。。。由于java8lambda表达式的出现所以传统的写法还是忘了吧。
由于本质是重写run()方法所以我们可以借助lambda表达式快速创建线程,如下:
Thread thread1=new Thread(() -> {
System.out.println(Thread.currentThread().getName());
});
lambda表达式,必须是函数式接口,必须只有一个方法.如果接口只有一个方法java默认它为函数式接口。为了正确使用Lambda表达式,需要给接口加个注解:@FunctionalInterface,如有两个方法,立刻报错!
2.2.2 关于同步
1.Synchronized
2.Lock类
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
synchronized与Lock的区别 :
两者区别:
1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。