文章目录
前言
随着JAVA程序员越来越卷,导致现在他们需要不断的学习更深的知识来达到卷的资本。本期系统教程主要介绍JUC,这一章就让我们从头来认识一下它吧,做为一名资深的JAVA程序员,你必需知道什么是JUC,JUC是用来做什么的,怎么用。这也是大厂面试必问技术之一。
一、JUC简介
1、出自哪位大神之手?
- JUC 是美国的一位大学教师 Doug Lea (道格·利)设计并开发出来的。
- Doug Lea 服务于纽约州立大学Oswego分校计算机学系的教师。
- Doug Lea 是 JCP(JAVA社区项目)中的一员。
- 让我们瞻仰一下大神的容貌,多向大神学习。
2、JUC是什么?
- JUC是 JDK中java.util.concurrent 包的简称(中文简称:并发工具包),它包含三个包:
- java.util.concurrent
- java.util.concurrent.atomic
- java.util.concurrent.locks
- 是2004年10月发布的JDK1.5新增用来编写并发相关的基础api。
- 目前JUC泛指JAVA多线程开发技术。
二、JUC主要解决什么问题?
JUC 主要解决的问题是:在高内聚低耦合的前提下,线程如何操作 资源类可以达到高并发高可用的效果?
先来学习一下几个基本概念
1、进程 、线程
- 进程:
- 操作系统可调配的最小单元。
- 有自己独立的空间。
- 比如:系统中运行的QQ、CF、王者,它们都是独立的进程。
- 线程:
- 线程是进程可中可调配的最小单元。
- 一个进程内可以包含多个线程。
- 如:360卫士里包含了许多功能,杀毒、下载软件等,它们是一个进程内不同的线程。
2、并发、并行
- 并发:
- 同一个功能被同时调用。
- 同一段程序被同时调用。
- 并行:
- 不同的功能被同时调用。
- 不同的程序被同时调用。
JUC就是解决多线程执行中遇到的问题,所以我们再来看一下JAVA里是怎么创建线程和操作线程的
3、JAVA创建线程的方式(模拟三种线程实现方式)
模拟一个多线程的需求:火车售票员 A、B、C三个人同时出售一列火车的10张票,售完为止。
1)继承Thread类(线程的初级用法)
使用JUC中的Lock实现不现线程对同一资源的操作
售票员类:
package com.juc.study;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 火车售票员
*/
public class TrainConductor extends Thread {
public TrainConductor() {
}
public TrainConductor(String name) {
super(name);
}
/**
* 售票
*/
public void saleTickets() {
// JUC中的锁,是轻量级的锁,实现类是可重入锁,
// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
Lock lock = new ReentrantLock();
lock.lock();
try {
if(Ticket.nums > 0) {
System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
@Override
public void run() {
for(int i = 70; i > 0; i--) {
saleTickets();
}
}
}
火车票类:
package com.juc.study;
public class Ticket {
public static int nums = 10;
}
执行类:
import com.juc.study.Ticket;
import com.juc.study.TrainConductor;
public class TestJUC {
public static void main(String[] args) {
// 新建三个售票员
TrainConductor trainConductorA = new TrainConductor("A");
TrainConductor trainConductorB = new TrainConductor("B");
TrainConductor trainConductorC = new TrainConductor("C");
// 开始售票
trainConductorA.start();
trainConductorB.start();
trainConductorC.start();
}
}
执行结果:
A 卖出第:9张, 还剩下:8
C 卖出第:8张, 还剩下:7
B 卖出第:10张, 还剩下:8
C 卖出第:6张, 还剩下:5
C 卖出第:4张, 还剩下:3
A 卖出第:7张, 还剩下:6
C 卖出第:3张, 还剩下:2
C 卖出第:1张, 还剩下:0
A 卖出第:2张, 还剩下:1
B 卖出第:5张, 还剩下:4
2)实现Runnable 接口(线程的初级用法)
与继承Thead类的写法有点区别,大家注意观察
售票员类:
package com.juc.study;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 售票员类
*/
public class TrainConductorRunnable implements Runnable{
/**
* 售票
*/
public void saleTickets() {
// JUC中的锁,是轻量级的锁,实现类是可重入锁,
// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
Lock lock = new ReentrantLock();
lock.lock();
try {
if(Ticket.nums > 0) {
System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
@Override
public void run() {
for(int i = 70; i > 0; i--) {
saleTickets();
}
}
}
火车票类(无变化):
package com.juc.study;
public class Ticket {
public static int nums = 10;
}
执行类:
import com.juc.study.Ticket;
import com.juc.study.TrainConductor;
import com.juc.study.TrainConductorRunnable;
public class TestJUC {
public static void main(String[] args) {
// 新建三个售票员
TrainConductorRunnable trainConductorA = new TrainConductorRunnable();
TrainConductorRunnable trainConductorB = new TrainConductorRunnable();
TrainConductorRunnable trainConductorC = new TrainConductorRunnable();
// 新建三个线程
Thread t1 = new Thread(trainConductorA, "A");
Thread t2 = new Thread(trainConductorB, "B");
Thread t3 = new Thread(trainConductorC, "C");
// 开始售票
t1.start();
t2.start();
t3.start();
}
}
执行结果:
A 卖出第:9张, 还剩下:7
C 卖出第:8张, 还剩下:7
A 卖出第:7张, 还剩下:6
B 卖出第:10张, 还剩下:7
A 卖出第:5张, 还剩下:4
C 卖出第:6张, 还剩下:5
A 卖出第:3张, 还剩下:2
B 卖出第:4张, 还剩下:3
A 卖出第:1张, 还剩下:0
C 卖出第:2张, 还剩下:1
3)内部类方式(线程的中级用法)
使用内部类实现是不需要继承Thread类或实现Runnable接口,大家仔细看
火车售票员类:
package com.juc.study;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 火车售票员(采用内部类的形式实现)
*/
public class TrainConductorInner {
/**
* 售票
*/
public void saleTickets() {
// JUC中的锁,是轻量级的锁,实现类是可重入锁,
// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
Lock lock = new ReentrantLock();
lock.lock();
try {
if(Ticket.nums > 0) {
System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
火车票类(无变化):
package com.juc.study;
public class Ticket {
public static int nums = 10;
}
执行类:
import com.juc.study.Ticket;
import com.juc.study.TrainConductorInner;
public class TestJUC {
public static void main(String[] args) {
Thread t1 = new Thread("A") {
@Override
public void run() {
for(int i = 70; i > 0; i--) {
TrainConductorInner a = new TrainConductorInner();
a.saleTickets();
}
}
};
t1.start();
Thread t2 = new Thread("B") {
@Override
public void run() {
for(int i = 70; i > 0; i--) {
TrainConductorInner b = new TrainConductorInner();
b.saleTickets();
}
}
};
t2.start();
Thread t3 = new Thread("C") {
@Override
public void run() {
for(int i = 70; i > 0; i--) {
TrainConductorInner c = new TrainConductorInner();
c.saleTickets();
}
}
};
t3.start();
}
}
4) 使用lamada 表达式实现(高级用法,也是企业中最常使用的方法)
lamada表达式写完之后有点长,如果看不懂可以给它格式化一下
火车售票员类(仍然使用内部类,没变化):
package com.juc.study;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 火车售票员(采用内部类的形式实现)
*/
public class TrainConductorInner {
/**
* 售票
*/
public void saleTickets() {
// JUC中的锁,是轻量级的锁,实现类是可重入锁,
// 意味着只要有人释放锁,另外一个人就可以重新拿到锁并执行。
Lock lock = new ReentrantLock();
lock.lock();
try {
if(Ticket.nums > 0) {
System.out.println(Thread.currentThread().getName() + "\t 卖出第:" + (Ticket.nums--) + "张,\t 还剩下:" + Ticket.nums);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
火车票类(没变化):
package com.juc.study;
public class Ticket {
public static int nums = 10;
}
执行类(这里使用lamada表达式):
import com.juc.study.Ticket;
import com.juc.study.TrainConductorInner;
public class TestJUC {
public static void main(String[] args) {
new Thread(()->{for(int i = 70; i > 0; i--){TrainConductorInner a = new TrainConductorInner(); a.saleTickets();}}, "A").start();
new Thread(()->{for(int i = 70; i > 0; i--){TrainConductorInner b = new TrainConductorInner(); b.saleTickets();}}, "B").start();
new Thread(()->{for(int i = 70; i > 0; i--){TrainConductorInner c = new TrainConductorInner(); c.saleTickets();}}, "C").start();
}
}
总结
最重要的一句话:在高内聚低耦合的前提下,线程操作资源类达到高并发高可用的效果就是JUC的任务。
JUC的入门就到这里,到这里大家应该会对JUC有点感觉了,感觉是不是挺好玩的,后面的章节更精彩,敬请期待。。。。。。