(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程⭐学妹已收藏
Posted java厂长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程⭐学妹已收藏相关的知识,希望对你有一定的参考价值。
🔥(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(一)⭐学妹已收藏
关于作者
- 作者介绍
🍓 博客主页:作者主页
🍓 简介:JAVA领域优质创作者🥇、一名在校大三学生🎓、在校期间参加各种省赛、国赛,斩获一系列荣誉🏆。
🍓 关注我:关注我学习资料、文档下载统统都有,每日定时更新文章,励志做一名JAVA资深程序猿👨💻。
JUC学习
文章目录
1、什么是JUC
源码+官方文档
JUC是 java util concurrent
面试高频问JUC~!
java.util 是Java的一个工具包
业务:普通的线程代码 Thread
Runnable: 没有返回值、效率相比于Callable 相对较低!
2、线程和进程
进程:一个程序,允许一个java程序会进程里面会出现一个java.exe;数据+代码+pcb
一个进程可以包含多个线程,至少包含一个线程!
Java默认有几个线程?2个线程! main线程、GC线程
线程:开了一个进程qq,聊天打字,消息提示(线程负责的)
对于Java而言:Thread、Runable、Callable进行开启线程的。
JAVA真的可以开启线程吗? 开不了的!
原因Java没有权限去开启线程、操作硬件的,这是一个native的一个本地方法,它调用的底层的C++代码。
并发、并行
并发: 多线程操作同一个资源。
- CPU 只有一核,模拟出来多条线程,那么我们就可以使用CPU快速交替,来模拟多线程。
并行: 多个人并排行走。
- CPU多核,多个线程可以同时执行。
public class Test {
public static void main(String[] args) {
//获取cpu的核数
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
并发编程的本质:充分利用CPU的资源!
线程的6个状态
public enum State {
//创建
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//超时等待
TIMED_WAITING,
//终止
TERMINATED;
}
面试题:谈一谈wait和sleep区别?
区别 | wait | sleep |
---|---|---|
操作的类 | Object | Thread |
锁的释放 | 会释放锁 | 抱着锁睡觉 |
范围 | 同步代码块中 | 任何地方 |
异常捕获 | 不需要捕获异常 | 需要捕获异常 |
3、Lock锁(重点)
synchronized锁问题
package com.zmz.day01;
/**
* @ProjectName: Juc
* @Package: com.zmz.day01
* @ClassName: TicketTest
* @Author: 张晟睿
* @Date: 2021/9/5 14:01
* @Version: 1.0
*/
//资源类 属性 + 方法 oop
class Ticket{
private int num = 50;
//卖票方式 synchronized 本质:队列 锁
public synchronized void sale(){
if(num > 0){
System.out.println(Thread.currentThread().getName()+ " 卖出了第"+ num +" 张票,剩余:"+ --num +" 张票");
}
}
}
public class TicketTest {
public static void main(String[] args) {
//多线陈操作
//并发:多个线程操作同一个资源ticket
Ticket ticket = new Ticket();
//@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket.sale();
}
},"C").start();
}
}
Lock接口
公平锁: 公平,必须先来后到~;
非公平锁: 不公平,可以插队;(默认为非公平锁)
使用Lock进行操作
package com.zmz.day01;/**
* @ProjectName: Juc
* @Package: com.zmz.day01
* @ClassName: TicketTest2
* @Author: 张晟睿
* @Date: 2021/9/5 16:15
* @Version: 1.0
*/
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*@ClassName TicketTest2
*@Description
*@Author 张晟睿
*@Date 2021/9/5
**/
class Ticket2{
/*
* 加锁三步
* 1.实例化lock对象
* 2.lock加锁
* 3.unlock解锁
* */
Lock l = new ReentrantLock();
private int num = 50;
//卖票方式 synchronized 本质:队列 锁
public void sale(){
//加锁
l.lock();
try {
//业务代码
if(num > 0){
System.out.println(Thread.currentThread().getName()+ " 卖出了第"+ num +" 张票,剩余:"+ --num +" 张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
l.unlock();
}
}
}
public class TicketTest2 {
public static void main(String[] args) {
//多线陈操作
//并发:多个线程操作同一个资源ticket
Ticket ticket = new Ticket();
//@FunctionalInterface 函数式接口 jdk1.8之后 lambda表达式
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 60; i++) {
ticket.sale();
}
},"C").start();
}
}
区别 | synchronized | lock |
---|---|---|
名称 | 属于关键字 | 属于对象 |
状态 | 不可以获取锁的状态 | 可以获取锁的状态 |
锁的管理 | 自动释放锁 | 需要手动加锁以及释放锁 |
线程 | 自己抱着锁 | 等待 |
可重入锁,不可以中断的,非公平的 | 可重入的,可以判断锁,可以自己设置公平锁和非公平锁 | |
代码同步 | 适合少量的代码同步 | 适合大量的代码同步 |
4、生产者消费者问题
synchronized版
package com.zmz.day01;
/**
* @ProjectName: Juc
* @Package: com.zmz.day01
* @ClassName: TicketTest3
* @Author: 张晟睿
* @Date: 2021/9/5 16:35
* @Version: 1.0
*/
/**
*@ClassName TicketTest3
*@Description
*@Author 张晟睿
*@Date 2021/9/5
**/
public class TicketTest3 {
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();
}
}
//判断等待 业务 唤醒
class Data{
private int number = 0;
// +1操作
public synchronized void increment() throws InterruptedException {
if(number != 0 ){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
// -1操作
public synchronized void decrement() throws InterruptedException{
if (number == 0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
}
问题存在,A线程B线程,现在如果我有四个线程A B C D!该怎么去解决问题
if判断改为While判断就可以解决虚假唤醒的问题。
package com.zmz.day01;
/**
* @ProjectName: Juc
* @Package: com.zmz.day01
* @ClassName: TicketTest3
* @Author: 张晟睿
* @Date: 2021/9/5 16:35
* @Version: 1.0
*/
/**
*@ClassName TicketTest3
*@Description
*@Author 张晟睿
*@Date 2021/9/5
**/
//线程之间的通讯问题:生产者和消费者的问题! 等待唤醒,通知唤醒
//线程交替执行 A B操作同一个资源
public class TicketTest3 {
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();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} 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();
}
}
//判断等待 业务 唤醒
class Data{
private int number = 0;
// +1操作
public synchronized void increment() throws InterruptedException {
while(number != 0 ){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
// -1操作
public synchronized void decrement() throws InterruptedException{
while (number == 0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
}
JUC版本的解决A B C D多线程的问题
package com.zmz.day01;
/**
* @ProjectName: Juc
* @Package: com.zmz.day01
* @ClassName: JucTest1
* @Author: 张晟睿
* @Date: 2021/9/5 19:34
* @Version: 1.0
*/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*@ClassName JucTest1
*@Description
*@Author 张晟睿
*@Date 2021/9/5
**/
public class JucTest1 {
public static void main(String[] args) {
Data2 data = new Data2();
new Thread(()->{for(int i=0;i<10;i++) {
data.increment();
}
},"A").start();
new Thread(()->{for(int i=0;i<10;i++) {
data.decrement();
}},"B").start();
new Thread(()->{for(int i=0;i<10;i++) {
data.increment();
}
},"C").start();
new Thread(()->{for(int i=0;i<10;i++) {
data.decrement();
}
},"D").start();
}
}
class Data2{
private int number = 0;
//lock锁
Lock l = new ReentrantLock()以上是关于(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程⭐学妹已收藏的主要内容,如果未能解决你的问题,请参考以下文章
建议收藏|熬夜爆肝万字文带你了解DOM,文末有彩蛋嗷!!!!✨✨✨
建议收藏|熬夜爆肝万字文带你了解DOM,文末有彩蛋嗷!!!!✨✨✨