一、基本概念
1、JUC 的定义
所谓 JUC 是指 Package java.util.concurrent(并发)
,但实际上包含三个java.util 下面的Java内部包:concurrent、concurrent.atomic和concurrent.locks
,分别是并发
、并发原子性
和并发加锁
。
2、进程与线程
进程,是计算机内部分配资源的基本单元,是一个具有一定独立功能的程序关于某个数据集合的一次性活动;在引入线程之前,计算机内部分配内存和CPU都是以进程为基本单位进行,引入线程之后进程作为分配内存等资源的基本单位,线程作为分配CPU的基本单位,因为线程的切换代价更低。
进程包含线程,线程共享进程的资源。简单理解,线程就是一种特殊的、轻量级的进程,除了一些必要的资源外,线程的创建几乎不需要什么资源。以Java的角度来理解,进程就是JVM,线程就是JVM里正在执行的某个Java方法。
3、并发与并行
并发是极短的时间段内交替执行,并行是同个时间点内同时执行,形象的理解就是打印机和投影仪的运行就是并行运行,网易云音乐和系统通知对影响的使用就是并发。
二、多线程示例
使用售票示例进行多线程演示线程在高内聚低耦合的前提下操作资源
1、synchronize 版
public class SaleTicket {
public static void main(String[] args) throws Exception {
Ticket ticket = new Ticket();
new Thread(new Runnable(){
@Override
public void run(){
for(int i=1;i<=60; i++){
ticket.sale();
}
}
},"t1").start();
new Thread(new Runnable(){
@Override
public void run(){
for(int i=1;i<=60; i++){
ticket.sale();
}
}
},"t2").start();
new Thread(new Runnable(){
@Override
public void run(){
for(int i=1;i<=60; i++){
ticket.sale();
}
}
},"t3").start();
}
}
class Ticket{
private int num = 50;
private int sale = 0;
public synchronized void sale(){
if (num>0){
System.out.println(Thread.currentThread().getName() +
"卖出第" + (++sale) + "张票,还剩" + (--num) + "张票");
}
}
}
注意:线程 start() 后只是进入就绪态,而不是运行态,什么时候运行看操作系统的调度。Java 的线程有创建态、就绪态、阻塞态、无限等待、定时等待和终结共5 种状态。wait 和 sleep 都会导致线程阻塞,而 wait 和 sleep 的区别在于:wait 会释放锁,sleep 不释放锁
。
2、ReentrantLock 版
ReentrantLock,即可重入锁
class Ticket{
private final ReentrantLock lock = new ReentrantLock();
private int num = 50;
private int sale = 0;
public void sale(){
lock.lock();
try {
if (num>0){
System.out.println(Thread.currentThread().getName() +
"卖出第" + (++sale) + "张票,还剩" + (--num) + "张票");
}
} finally {
lock.unlock();
}
}
}public class SaleTicket {
public static void main(String[] args) throws Exception {
Ticket ticket = new Ticket();
new Thread(
() -> {
for (int i = 1; i < 55; i++) ticket.sale();
},
"A")
.start();
new Thread(
() -> {
for (int i = 1; i < 55; i++) ticket.sale();
},
"B")
.start();
new Thread(
() -> {
for (int i = 1; i < 55; i++) ticket.sale();
},
"C")
.start();
}
}
class Ticket {
private final Lock lock = new ReentrantLock();
private int num = 150;
private int sale = 0;
public void sale() {
lock.lock();
try {
if (num > 0) {
System.out.println(
Thread.currentThread().getName() + "卖出第" + (++sale) + "张票,还剩" + (--num) + "张票");
}
} finally {
lock.unlock();
}
}
}