【JUC 一】线程 进程 synchronized Lock锁 生产者 消费者 8锁 线程安全集合类

业务: 普通的线程代码, 之前都是用的thread或者runnable接口

但是相比于callable来说,thread没有返回值,且效率没有callable高

2、线程和进程

=======

  • 进程

一个运行中的程序的集合;一个进程往往可以包含多个线程,至少包含一个线程

  • java默认有几个线程?

两个。 main线程、gc线程

  • 线程

线程(thread)是操作系统能够进行运算调度的最小单位

  • 对于java而言如何创建thread

继承自thread

实现runnable接口

实现callable接口

  • Java真的可以开启线程吗?

开不了的。底层是用native关键词修饰。调用本地实现(start0())

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();

并发,并行

并发编程: 并发和并行

并发(多线程操作同一个资源,交替执行)

  • CPU一核, 模拟出来多条线程,天下武功,唯快不破,快速交替

并行(多个人一起行走, 同时进行)

  • CPU多核,多个线程同时进行 ; 使用线程池操作

public static void main(String[] args) {

//获取CPU核数

//CPU 密集型,IO密集型

System.out.println(Runtime.getRuntime().availableProcessors());

}

并发编程的本质: 充分利用CPU的资源

  • 线程有几个状态?

public enum State {

// 新生

NEW,

// 运行

RUNNABLE,

// 阻塞

BLOCKED,

// 等待

WAITING,

//超时等待

TIMED_WAITING,

//终止

TERMINATED;

}

| 区别 | wait | sleep |

| — | — | — |

| 来自不同的类 | object类 | 线程类 |

| 锁的释放不同 | 会释放锁 | 不会释放锁 |

| 使用范围不同 | 必须在同步代码中 | 可以在任何地方睡 |

TimeUnit

TimeUnit.SECONDS.sleep(3);//睡眠3秒

3、Lock锁(重点)

===========

3.1、传统synchronized


本质: 队列和锁,放在方法上锁的是this,放在代码块中锁的是()里面的对象

synchronized(obj){

}

3.2、Lock 接口


  • reentrantLock构造器

非公平锁:NonfairSync()

十分不公平,可以插队(默认)

公平锁:FairSync()

十分公平,先来后到,一定要排队

public ReentrantLock() {

sync = new NonfairSync(); //无参默认非公平锁

}

public ReentrantLock(boolean fair) {

sync = fair ? new FairSync() : new NonfairSync();//传参为true为公平锁

}

3.3、synchronized 和 lock 区别


| 比较 | Lock | synchronized |

| — | — | — |

| 类型 | java接口 | 内置关键字 |

| 开启释放 | 显式锁手动 开启 和 关闭 | 隐式锁

出了作用域自动释放 |

| 代码锁 | 支持 | 支持 |

| 方法锁 | 不支持 | 支持 |

| 锁状态 | 可以判断是否获取到了锁 | 无法判断获取锁的状态 |

| 线程阻塞 | Lock锁就不一定会等待下去 | 线程1(获得锁,阻塞),线程2(等待) |

| 可重入性 | 可重入的,可以判断锁 | 可重入锁,不可以中断的 |

| 公平性 | 默认非公平的(可设置) | 非公平的 |

| 性能 | 性能更好

JVM将花费较少的时间来调度 | 性能一般

JVM将花费较多的时间来调度管理 |

| 扩展性 | 有更好的扩展性(提供更多的子类) | 不支持 |

| 适用场景 | 适合锁大量的同步代码 | 适合锁少量的代码同步问题 |

4、生产者和消费者问题

===========

面试高频:单例模式、八大排序、生产者消费者、死锁

4.1、synchronized实现


wait、notify 必须在 synchronizied 声明的代码中,否则会抛出异常 java.lang.IllegalMonitorStateException

package providerConsumer;

/**

  • @author ajun

  • Date 2021/7/3

  • @version 1.0

  • synchronized版生产者消费者

*/

public class Syn {

public static void main(String[] args) {

Data data = new Data();

//线程1

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data.increment();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“A”).start();

//线程2

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data.decrement();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“B”).start();

//线程3

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data.increment();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“C”).start();

//线程4

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data.decrement();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“D”).start();

}

}

class Data{

private int num;

public int getNum() {

return num;

}

//增加

public synchronized void increment() throws InterruptedException {

//判断等待

//用while,不用if,防止虚假唤醒

while(num!=0){

this.wait();

}

//业务代码

num++;

System.out.println(Thread.currentThread().getName() + " --> " + num);

//通知

this.notifyAll();

}

//减少

public synchronized void decrement() throws InterruptedException {

//判断等待

//用while,不用if,防止虚假唤醒

while(num == 0){

this.wait();

}

//业务代码

num–;

System.out.println(Thread.currentThread().getName() + " --> " + num);

//通知

this.notifyAll();

}

}

  • 可能存在的问题

虚假唤醒

在判断等待时,如果用 if ,当线程多的时候,可能会有虚假唤醒

解决办法

if 判断改为 while 判断

因为 if 只会执行一次,执行完会接着向下执行 if()外边的

而 while 不会,直到条件满足才会向下执行 while()外边的

4.2、JUC实现


在JUC中,Lock 替换 synchronized,await 替换 wait,signal 替换 notify。(signal 信号)

package providerConsumer;

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

/**

  • @author ajun

  • Date 2021/7/3

  • @version 1.0

*/

public class Loc {

public static void main(String[] args) {

Data2 data2 = new Data2();

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data2.increment();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“A”).start();

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data2.decrement();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“B”).start();

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data2.increment();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“C”).start();

new Thread(() -> {

for (int i = 0; i < 5; i++) {

try {

data2.decrement();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

},“D”).start();

}

}

class Data2{

private int num = 0;

Lock lock = new ReentrantLock();//定义锁

Condition condition = lock.newCondition();//定义同步监视器

public int getNum() {

return num;

}

//增加

public void increment() throws InterruptedException {

lock.lock();//加锁

try {

//判断等待

while (num != 0){

condition.await();//等待

}

//业务代码

num++;

System.out.println(Thread.currentThread().getName() + " --> " + num);

//通知

condition.signalAll();

} finally {

lock.unlock();//解锁

}

}

//减少

public void decrement() throws InterruptedException {

lock.lock();//加锁

try {

//判断等待

while (num == 0){

condition.await();//等待

}

//业务代码

num–;

System.out.println(Thread.currentThread().getName() + " --> " + num);

//通知

condition.signalAll();

} finally {

lock.unlock();//解锁

}

}

}

Condition实现精准通知唤醒

5、8锁现象

======

8锁就是关于锁的八个现象

① 非静态同步方法的默认锁是 this,静态同步方法的默认锁是 class

面试结束复盘查漏补缺

每次面试都是检验自己知识与技术实力的一次机会,面试结束后建议大家及时总结复盘,查漏补缺,然后有针对性地进行学习,既能提高下一场面试的成功概率,还能增加自己的技术知识栈储备,可谓是一举两得。

以下最新总结的阿里P6资深Java必考题范围和答案,包含最全MySQL、Redis、Java并发编程等等面试题和答案,用于参考~

重要的事说三遍,关注+关注+关注!

历经30天,说说我的支付宝4面+美团4面+拼多多四面,侥幸全获Offer

image.png

更多笔记分享

历经30天,说说我的支付宝4面+美团4面+拼多多四面,侥幸全获Offer

id decrement() throws InterruptedException {

lock.lock();//加锁

try {

//判断等待

while (num == 0){

condition.await();//等待

}

//业务代码

num–;

System.out.println(Thread.currentThread().getName() + " --> " + num);

//通知

condition.signalAll();

} finally {

lock.unlock();//解锁

}

}

}

Condition实现精准通知唤醒

5、8锁现象

======

8锁就是关于锁的八个现象

① 非静态同步方法的默认锁是 this,静态同步方法的默认锁是 class

面试结束复盘查漏补缺

每次面试都是检验自己知识与技术实力的一次机会,面试结束后建议大家及时总结复盘,查漏补缺,然后有针对性地进行学习,既能提高下一场面试的成功概率,还能增加自己的技术知识栈储备,可谓是一举两得。

以下最新总结的阿里P6资深Java必考题范围和答案,包含最全MySQL、Redis、Java并发编程等等面试题和答案,用于参考~

重要的事说三遍,关注+关注+关注!

[外链图片转存中…(img-wTr5OrQQ-1720081938169)]

[外链图片转存中…(img-WldXciyO-1720081938170)]

更多笔记分享

[外链图片转存中…(img-rpo3dN0a-1720081938171)]

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值