多线程进阶——JUC并发编程之前夜

编程

文档地址:https://docs.oracle.com/javase/8/docs/api/

首先我们看看什么是JUC

其次我们看看JUC都有哪些东西

于是我们可以总结下JUC可以分为五大类

1、同步工具类

2、lock类

3、原子类

4、集合相关类

5、Executor框架相关类

2、JUC入门前言——唠嗑 线程和进程

线程、进程,如果不能使用一句话说出来,说明技术不扎实!

进程:一个程序,QQ.exe  Music.exe  程序的集合;
一个进程往往可以包含多个线程,至少包含一个!
Java默认有几个线程? 2 个   mian、GC
线程:开了一个进程 Typora,写字,自动保存(线程负责的) 对于Java而言:Thread、Runnable、Callable

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

并发、并行

并发编程:并发、并行
并发(多线程操作同一个资源)
    CPU 一核 ,模拟出来多条线程,天下武功,唯快不破,快速交替
并行(多个人一起行走)
    CPU 多核 ,多个线程可以同时执行; 线程池

public class Test1 {

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区别

1、来自不同的类 wait => Object
sleep => Thread

2、关于锁的释放 wait 会释放锁,sleep 睡觉了,抱着锁睡觉,不会释放!
3、使用的范围是不同: wait必须在同步代码块中,sleep可以在任何地方睡

3、Lock锁(重点)

传统Synchronized

/**

* 真正的多线程开发,公司中的开发,降低耦合性

* 线程就是一个单独的资源类,没有任何附属的操作!

* 1、 属性、方法

*/

public class SaleTicketDemo01 {

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

class Ticket {

// 属性、方法

private int number = 30;

// 卖票的方式

// synchronized 本质: 队列,锁

public synchronized void sale(){

if (number>0){

System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);

}

}

}

Lock接口

实现类:可重入锁、读锁、写锁

  public ReentrantLock() {

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

}

/**

* Creates an instance of {@code ReentrantLock} with the

* given fairness policy.

*

* @param fair {@code true} if this lock should use a fair ordering policy

*/

public ReentrantLock(boolean fair) {//公平锁

sync = fair ? new FairSync() : new NonfairSync();

}

公平锁:十分公平:可以先来后到

非公平锁:十分不公平:可以插队 (默认)
案例代码:

public class SaleTicketDemo02  {

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(); // 解锁

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(); // 解锁

}

}

}

Synchronized 和 Lock 区别

1、Synchronized   内置的Java关键字,  Lock 是一个Java类

2、Synchronized  无法判断获取锁的状态,Lock  可以判断是否获取到了锁
3、Synchronized  会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁

4、Synchronized   线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下 去;
5、Synchronized    可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以 自己设置);
6、Synchronized     适合锁少量的代码同步问题,Lock  适合锁大量的同步代码! 

锁是什么呢,如何判断锁是谁?

4、生产者和消费者问题

面试的:单例模式、排序算法、生产者和消费者、死锁

生产者和消费者问题 Synchronized   版

/**

* 线程之间的通信问题:生产者和消费者问题! 等待唤醒,通知唤醒

* 线程交替执行 A B 操作同一个变量 num = 0

* A num+1

* B num-1

*/

public class A {

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

}

}

// 判断等待,业务,通知

class Data{ // 数字 资源类

private int number = 0;

//+1

public synchronized void increment() throws InterruptedException {

if (number!=0){ //0

// 等待

this.wait();

}

number++;

System.out.println(Thread.currentThread().getName()+"=>"+number);

// 通知其他线程,我+1完毕了

this.notifyAll();

}

//-1

public synchronized void decrement() throws InterruptedException {

if (number==0){ // 1

// 等待

this.wait();

}

number--;

System.out.println(Thread.currentThread().getName()+"=>"+number);

// 通知其他线程,我-1完毕了

this.notifyAll();

}

}

问题存在,A  B  C D  4 个线程! 虚假唤醒,注意要把 if 判断改为 while ,因为 if 只会判断一次!

JUC版的生产者和消费者问题

通过Lock找到Condition

代码实现:

public class B  {

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

}

}

// 判断等待,业务,通知

class Data2{ // 数字 资源类

private int number = 0;

Lock lock = new ReentrantLock();

Condition condition = lock.newCondition();

//condition.await(); // 等待

//condition.signalAll(); // 唤醒全部

//+1

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

}

}

//-1

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

}

}

}

任何一个新的技术,绝对不是仅仅只是覆盖了原来的技术,优势和补充!

Condition 精准的通知和唤醒线程

/**

* A 执行完调用B,B执行完调用C,C执行完调用A

*/

public class C {

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

}

}

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()+"=>BBBBBBBBB");

// 唤醒,唤醒指定的人,c

number = 1;

condition1.signal();

} catch (Exception e) {

e.printStackTrace();

} finally {

lock.unlock();

}

}

}

本文参考:狂神说java

https://www.bilibili.com/video/av90007319

以上是 多线程进阶——JUC并发编程之前夜 的全部内容, 来源链接: utcz.com/z/513804.html

回到顶部