1. 什么是JUC
java.util 工具包
业务:普通的线程 Thread
Runnable 没有返回值、效率相比 Callable 相对较低
2. 线程和进程
进程:一个程序,QQ.exe Music.exe 程序的集合
线程: 一个进程往往包含多个线程,至少包含一个
java 默认有几个线程? 2个 main 、 GC
Thread、 Runnable、 Callable
Java真的可以开线程吗?
不能,Java只能通过 native 调用底层C++
并发、并行
并发编程:并发、并行
并发(多个线程操作同一个资源)
并行(同时执行)
1 2 3 4
| public static void main(String[] args) { System.out.println(Runtime.getRuntime().availableProcessors()); }
|
并发编程本质:充分利用CPU资源
线程有几个状态
6个状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; }
|
wait、sleep 区别
- 来自不同的类,wait => Object , sleep =>
Thread
- wait会释放锁,sleep不会释放锁
- wait 必须在同步代码块中 , sleep
可以在任何地方使用
- wait 不需要捕获异常, sleep 必须捕获异常
3.Lock锁 (重点)
传统: Synchronized
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package com.demo01;
public class SaleTicketDemo01 { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(() -> { for(int i = 0; i < 40; i++){ ticket.sale(); } }, "A").start();
new Thread(() -> { for(int i = 0; i < 40; i++){ ticket.sale(); }
}, "B").start();
new Thread(() -> { for(int i = 0; i < 40; i++){ ticket.sale(); } }, "C").start(); } }
class Ticket { private int number = 50;
public synchronized void sale() { if (number > 0) { System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "票,剩余:" + number); } } }
|
Lock 接口
1 2 3 4 5 6
| Lock l = ...; l.lock(); try { } finally { l.unlock(); }
|
- ReentrantLock:常用、可重入锁
- ReentrantReadWriteLock.ReadLock:读锁
- ReentrantReadWriteLock.WriteLock:写锁
1 2 3
| public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
|
默认非公平锁
公平锁:先来后到
非公平锁:可以插队(默认)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package com.demo01;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;
public class SaleTicketDemo02 { public static void main(String[] args) { Ticket2 ticket = new Ticket2();
new Thread(() -> { for(int i = 0; i < 40; i++){ ticket.sale(); } }, "A").start();
new Thread(() -> { for(int i = 0; i < 40; i++){ ticket.sale(); }
}, "B").start();
new Thread(() -> { for(int i = 0; i < 40; i++){ ticket.sale(); } }, "C").start(); } }
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() + "卖出了第" + (number--) + "票,剩余:" + number); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
|
Synchronized 和 Lock 区别
- Synchronized 是Java内置的关键字,Lock
是一个Java类
- Synchronized 无法判断获取锁的状态,Lock
可以判断是否获取到了锁
- Synchronized 会自动释放锁,Lock
必须要手动释放锁。如果不释放会导致 死锁
- Synchronized 线程1(获得锁,阻塞)、线程2(等待);
Lock锁就不一定一直等待
- Synchronized 可重入锁,不可以中断的,非公平; Lock
可重入锁,可以判断锁,非公平(可以自己设置)
- Synchronized 适合少量代码同步问题;Lock
适合大量同步代码
4. 生产者和消费者问题
传统方式:
Condition方式:
Condition
因素的 Object
监测方法(
wait
, notify
和
notifyAll
为不同的对象给在每个对象的多个等待集的影响,结合
Lock
实现任意使用。在 Lock
取代
synchronized
方法和语句的使用,一个
Condition
取代对象监视器的使用方法。