什么是JUC
JUC是java.util.concurrent的简写。在jdk官方手册中可以看到juc相关的jar包有三个。
用中文概括一下,JUC的意思就是java并发编程工具包!
回顾线程和进程
- 进程:一个运行中的程序!是操作系统进行资源分配和调度的基本单位!一个进程可以包含多个线程;java默认有两个线程:main线程;GC线程!
- 线程:线程是操作系统中进行运算调度的最小单位!
java可以开启线程吗?
不可以;因为线程的开启是调用的本地方法start0(),其底层使用的是C++;java无法直接操作硬件!
并发和并行:
并发:多个线程操作同一个资源!
- 一皇两后就是并发;例如CPU一核的时候,线程之间快速交替,模拟多条线程!
并行:多个人一起行走;可以使用线程池!
- 两皇一后就是并行 ;例如CPU多核,多个线程可以同时执行!
用代码查看电脑的线程数:
public class Test1 {
public static void main(String[] args) {
//获取CPU的核数
//CPU密集型,IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
并发编程的本质:充分利用CPU的资源!
线程的几个状态
通过底层可以知道有6个:
NEW(新生),RUNNABLE(运行), BLOCKED(阻塞), WAITING(等待),TIMED_WAITING(超时等待), TERMINATED(终止);
wait和sleep的区别
- 来自不同的类;wait来自Object的类;sleep来自Thread类;
- 关于锁的释放:wait会释放锁,sleep不会释放锁!
- 使用的范围不同:wait必须在同步代码块中;sleep可以在任何地方!
- 是否需要捕获异常:只要是线程都会存在中断异常!
LOCK锁(重点!)
传统Synchronized
//仍然使用基本的卖票例子
/**
* 线程就是一个单独的资源类,没有任何的附属操作
* 1.属性、方法
*/
public class SaleTick {
public static void main(String[] args) {
//并发:多线程操作同一个类;把资源类丢入线程
Ticket ticket = new Ticket();
// 使用lambda表达式 (参数)->{代码} 最好不要写一行,代码可读性变差了!
new Thread(()->{ for(int i = 1;i<50;i++){ ticket.sale(); } },"A").start();
new Thread(()->{ for(int i = 1;i<50;i++){ ticket.sale(); } },"B").start();
new Thread(()->{ for(int i = 1;i<50;i++){ ticket.sale(); } },"C").start();
}
}
//这里不去实现Runnable接口,可以实现降低耦合!
class Ticket{
//属性、方法
private int number = 50;
//卖票的方式
public synchronized void sale(){
if(number >0){
System.out.println(Thread.currentThread().getName() + "卖出了" + number-- +"票,剩余:" + number +"张票");
}
}
}
Lock接口
通过API文档:使用Lock是在用之前加锁,在用完之后解锁。
Lock接口有三个实现类:分别如下:
常用的可重用锁的底层!
公平锁:十分公平,先来后到,需要排队!
非公平锁:可以插队!(默认)
使用Lock的代码相比于上面只是业务部分改变了:
//使用Lock锁三部曲
/**
* 1.new 一个锁 new ReentrantLock();
* 2.加锁
* 3.解锁
*/
class Ticket{
//属性、方法
private int number = 50;
Lock l = new ReentrantLock();
public void sale(){
l.lock();
try {
//业务代码 Ctrl+Alt+T 快捷键包含业务代码
if(number >0){
System.out.println(Thread.currentThread().getName() + "卖出了" + number-- +"票,剩余:" + number +"张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
l.unlock();
}
}
}
Synchronized和Lock的区别
通过上面的代码我们可以发现他们之间的区别如下:
- Synchronized是一个内置的java关键字;Lock是一个java类;
- Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁;
- Synchronized会自动释放锁,Lock锁必须手动释放锁,如果不释放锁,就会造成死锁!
- Synchronized中假如有两个线程:当线程1获得锁的时候,线程2等待;当线程1阻塞时,线程2会一直傻傻的等;Lock锁就不一定会等待下去,因为有一个tryLock()方法会尝试去获得锁!
- Synchronized可重入锁,不可中断的,非公平;Lock可重入锁,可以判断锁,可以自己设置公平与非公平!
- Synchronized适合锁少量的代码同步问题,Lock适合锁大量的同步代码!