一、什么是JUC
1、概念
- JUC就是 java.util 下的工具包、包、分类等。
二、线程知识回顾
1、进程与线程
-
进程:
①、一个程序,QQ.exe Music.exe 程序的集合;
②、一个进程往往可以包含多个线程,至少包含一个!
③、Java默认有2个线程? mian、GC -
线程:
①、例如编写文档时,编写的操作和自动保存属于两个不同的线程
②、对于Java而言提供了:Thread、Runnable、Callable操作线程。
2、Java是否可以直接开启线程?
- 源码分析
public synchronized void start() {
/**
* This method is not invoked for the main method thread
* or "system" group threads created/set up by the VM. Any new
* functionality added to this method in the future may have to
* also be added to the VM.A zero status value corresponds to
* state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/*
* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented.
*/
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
// 本地方法,底层操作的是C++ ,Java 无法直接操作硬件
private native void start0();
java时不能直接开启线程的,最后是通过调用本地方法,底层为c++操作
3、并发与并行
并发:
- 多线程操作同一个资源。
- 一核CPU,模拟出来多条线程,快速交替。
并行:
- 多核CPU ,多个线程可以同时执行
public class Test1 {
public static void main(String[] args) {
// 获取cpu的核数
System.out.println(Runtime.getRuntime().availableProcessors());
// 如果电脑是8核,则结果输出8
}
}
并发编程的本质:充分利用CPU的资源
4、线程的6个状态
public enum State {
NEW:线程新生状态
RUNNABLE:线程运行中
BLOCKED:线程阻塞状态
WAITING:线程等待状态,死等
TIMED_WAITING:线程超时等待状态,超过一定时间就不再等
TERMINATED:线程终止状态,代表线程执行完毕
}
5、wait和sleep的区别
①、来自不同的类
- wait => Object
- sleep => Thread
②、关于锁的释放
- wait 会释放锁
- sleep 睡觉了,抱着锁睡觉,不会释放
③、使用的范围是不同的
- wait 必须在同步代码块中使用
- sleep 可以在任何地方睡眠
三、Synchronized锁和Lock锁
1、Synchronized锁买票例子
public class SaleTicketTDemo01 {
/*
* 真正的多线程开发,公司中的开发,降低耦合性
* 线程就是一个单独的资源类,没有任何附属的操作!
* 1、 属性、方法
*/
public static void main(String[] args) {
//并发:多个线程同时操作一个资源类,把资源类丢入线程
Ticket ticket = new Ticket();
// @FunctionalInterface 函数式接口,jdk1.8 lambada表达式
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();
}
}
//资源类 OOP
class Ticket {
//属性、方法
private int number = 50;
// 卖票的方式
// synchronized 本质: 队列,锁
public synchronized void sale() {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了" +
(50-(--number)) + "张票,剩余:" + number + "张票");
}
}
}
2、Lock锁
- 公平锁:十分公平,线程执行顺序按照先来后到顺序
- 非公平锁:十分不公平:可以插队 (默认锁)
- Lock锁买票例子
public class SaleTicketTDemo02 {
public static void main(String[] args) {
//并发:多个线程同时操作一个资源类,把资源类丢入线程
Ticket2 ticket = new Ticket2();
// @FunctionalInterface 函数式接口,jdk1.8 lambada表达式
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();
}
}
//Lock 3步骤
// 1. new ReentrantLock();
// 2. lock.lock() 加锁
// 3. lock.unlock() 解锁
class Ticket2 {
//属性、方法
private int number = 50;
Lock lock = new ReentrantLock();
// 卖票方式
public void sale() {
lock.lock();// 加锁
try {
// 业务代码
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了" +
(50 - (--number)) + "张票,剩余:" + number + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();// 解锁
}
}
}
Synchronized 和 Lock 区别:
- Synchronized 是内置的Java关键字; Lock 是一个Java类
- Synchronized 无法判断获取锁的状态;Lock 可以判断是否获取到了锁
- Synchronized 会自动释放锁;lock 必须要手动释放锁!如果不释放锁,就会死锁
- Synchronized 线程 1(获得锁,如果线程1阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去
- Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以判断锁,非公平(可以自己设置)
- Synchronized 适合锁少量的代码同步问题;Lock 适合锁大量的同步代码