JUC并发编程
1. 线程和进程
-
进程: 一个程序,
QQ.exe
Music.exe
程序的集合; 一个进程往往可以包含多个线程,至少包含一个。 -
Java
默认有几个线程: 2 个(mian
、GC
)。 -
线程:开了一个进程
Typora
,写字,自动保存(线程负责的) -
创建线程(对于Java而言):
Thread
、Runnable
、Callable
。 -
Java
真的可以开启线程吗? 不可以开启线程。public synchronized void start() { if (threadStatus != 0)throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } } // 本地方法,底层的C++ ,Java 无法直接操作硬件 private native void start0();
-
并发(多线程操作同一个资源):
CPU
一核 ,模拟出来多条线程,快速交替 。 -
并行(多个人一起行走):
CPU
多核 ,多个线程可以同时执行; 线程池。public static void main(String[] args) { //获取cpu的核数 //CPU密集型,IO密集型 System.out.println(Runtime.getRuntime().availableProcessors()); }
-
线程有几个状态。
public enum State { //尚未启动的线程的线程状态 NEW, //可运行线程的线程状态 RUNNABLE, //等待监视器锁的阻塞线程的线程状态 BLOCKED, //等待线程的线程状态 WAITING, //具有指定等待时间的等待线程的线程状态 TIMED_WAITING, //终止线程的线程状态 TERMINATED; }
-
wait / sleep
区别:- 来自不同的类:
wait => Object
,sleep => Thread
- 锁的释放:
wait
会释放锁,sleep
不会释放锁 - 使用的范围不同:
wait
必须在同步代码块中,sleep
可以在任何地方
- 来自不同的类:
2. Lock锁
-
传统
Synchronized
:public static void main(String[] args) { // 并发:多线程操作同一个资源类, 把资源类丢入线程 Ticket ticket = new Ticket(); //@FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{ 代码 } new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "A").start(); new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "B").start(); new Thread(() -> { for (int i = 1; i < 40; i++) { ticket.sale(); } }, "C").start(); } //资源类OOP static class Ticket { //属性、方法 private int number = 30; //卖票的方式 //synchronized 本质: 队列,锁 public synchronized void sale() { if (number > 0) { System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余:" + number); } } } //结果 A卖出了30票,剩余:29 A卖出了29票,剩余:28 ... A卖出了3票,剩余:2 A卖出了2票,剩余:1 A卖出了1票,剩余:0
-
Lock
接口:public static void main(String[] args) { // 并发:多线程操作同一个资源类, 把资源类丢入线程 Ticket2 ticket = new Ticket2(); // @FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{ 代码 } new Thread(() -> { for (int i = 1; i < 40; i++) ticket.sale(); }, "A").start(); new Thread(() -> { for (int i = 1; i < 40; i++) ticket.sale(); }, "B").start(); new Thread(() -> { for (int i = 1; i < 40; i++) ticket.sale(); }, "C").start(); } // Lock三部曲 // 1、new ReentrantLock(); // 2、lock.lock(); //加锁 // 3、finally=> lock.unlock(); //解锁 static class Ticket2 { //属性、方法 private int number = 30; 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(); // 解锁 } } } //结果 A卖出了30票,剩余:29 A卖出了29票,剩余:28 ... A卖出了3票,剩余:2 A卖出了2票,剩余:1 A卖出了1票,剩余:0
-
Synchronized
和Lock
区别:Synchronized
内置的Java
关键字,Lock
是一个Java
类。Synchronized
无法判断获取锁的状态,Lock
可以判断是否获取到了锁。Synchronized
会自动释放锁,lock
必须要手动释放锁!如果不释放锁,死锁。Synchronized
线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock
锁就不一定会等待下去。Synchronized
可重入锁,不可以中断的,非公平;Lock
,可重入锁,可以 判断锁,非公平(可以自己设置)。Synchronized
适合锁少量的代码同步问题,Lock
适合锁大量的同步代码。
3. 生产者和消费者问题
-
生产者和消费者问题
Synchronized
版:public static void main(String[] args) { Data data = new Data(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); } // 判断等待,业务,通知 static class Data { // 数字 资源类 private int number = 0; public synchronized void increment() throws InterruptedException { if (number != 0) { //0 // 等待 this.wait(); } number++; System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我+1完毕了 this.notifyAll(); } public synchronized void decrement() throws InterruptedException { if (number == 0) { // 1 // 等待 this.wait(); } number--; System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我-1完毕了 this.notifyAll(); } } //结果 A=>1 B=>0 A=>1 B=>0 A=>1 B=>0 ...
-
问题存在,
A B C D
4个线程! 虚假唤醒:
-
JUC
版的生产者和消费者问题:public static void main(String[] args) { Data2 data = new Data2(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "A").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "B").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.increment(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "C").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { try { data.decrement(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "D").start(); } // 判断等待,业务,通知 static class Data2 { // 数字 资源类 private int number = 0; Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); //condition.await(); //等待 //condition.signalAll(); //唤醒全部 public void increment() throws InterruptedException { lock.lock(); try { //业务代码 while (number != 0) { //0 //等待 condition.await(); } number++; System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我+1完毕了 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public synchronized void decrement() throws InterruptedException { lock.lock(); try { while (number == 0) { // 1 // 等待 condition.await(); } number--; System.out.println(Thread.currentThread().getName() + "=>" + number); // 通知其他线程,我-1完毕了 condition.signalAll(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } //结果 A=>1 B=>0 A=>1 B=>0 A=>1 B=>0 ... C=>1 D=>0 C=>1 D=>0 C=>1 D=>0 ...
-
Condition
精准的通知和唤醒线程:public static void main(String[] args) { Data3 data = new Data3(); new Thread(() -> { for (int i = 0; i < 10; i++) { data.printA(); } }, "A").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { data.printB(); } }, "B").start(); new Thread(() -> { for (int i = 0; i < 10; i++) { data.printC(); } }, "C").start(); } static class Data3 { //资源类 Lock private Lock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); private int number = 1; // 1A 2B 3C public void printA() { lock.lock(); try { //业务,判断-> 执行-> 通知 while (number != 1) { //等待 condition1.await(); } System.out.println(Thread.currentThread().getName() + "=>AAAAAAA"); // 唤醒,唤醒指定的人,B number = 2; condition2.signal(); } catch ( Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printB() { lock.lock(); try { //业务,判断-> 执行-> 通知 while (number != 2) { condition2.await(); } System.out.println(Thread.currentThread().getName() + "=>BBBBBBBBB"); // 唤醒,唤醒指定的人,c number = 3; condition3.signal(); } catch ( Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printC() { lock.lock(); try { //业务,判断-> 执行-> 通知 // 业务,判断-> 执行-> 通知 while (number != 3) { condition3.await(); } System.out.println(Thread.currentThread().getName() + "=>CCCCCCC"); // 唤醒,唤醒指定的人,c number = 1; condition1.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } //结果 A=>AAAAAAA B=>BBBBBBBBB C=>CCCCCCC A=>AAAAAAA B=>BBBBBBBBB C=>CCCCCCC A=>AAAAAAA B=>BBBBBBBBB C=>CCCCCCC ...