一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
1. JUC
1.1 概述
JUC:java.util.concurrent并发编程包
进程:系统中正在运行的一个程序。
线程:程序执行的最小单元
Wait:Object类的方法,会释放锁(当前线程有锁的情况下)
Sleep:Thread类的方法,不会释放锁,不会占用锁
两个方法都会被interrupted方法中断
并发:多个线程访问一个资源;春运抢票
并行:多个线程一起执行一个任务,每个线程执行一部分操作;边刷牙边烧水
1.2 Synchronized和Lock
Sychronized
使用方式
针对上锁的操作方法,可以实现每次只允许一个线程访问
public sychronized int saleTicket(){
.....
}
Lock
使用方式
//创建可重入锁
private final ReenrantLock lock=new ReentrantLock();
public void lockSale(){
//加锁
lock.lock();
...
//解锁
lock.unlock();
}
概念和实现原理
可重入锁:在进入操作方法的第一步上锁,出操作方法的最后一步解锁
Lock和Sychronized的区别
1、Lock
需要手动上锁和释放锁,Sychronized
不需要手动操作(异常自动释放锁),只需要加到对应的操作方法上即可
2、Lock
比Sychronized
功能强大。Lock
可扩展性更强(知道是否获取到锁、可以让那个等待线程响应中断)
3、Lock
性能要高于Sychronized
1.3 并发编程思路
- 创建资源类,在类中创建属性和操作方法
- 创建多个线程,调用资源类的操作方法
针对这个操作方法赋予锁
/**
* 1. 创建资源类,创建属性和操作方法
* 2. 创建多个线程去调用资源类的操作方法
*/
public class SaleTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
//创建多个线程,每个线程都去调用资源类的操作方法
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
ticket.sale();
}
}
}, "A").start();
//lambda表达式写法
new Thread(()->{
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
ticket.sale();
}
}
}, "B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
ticket.sale();
}
}
}, "C").start();
}
}
class Ticket {
private int ticketNum = 10000;
/**
* 使用Synchronized来加锁
* 1. 操作方法上加上synchronized关键字
* 2. 业务操作
*/
public void synchronizedSale() {
//public synchronized void synchronizedSale(){}一样的操作,都是对对象加锁
synchronized (this) {
if (ticketNum > 0) {
System.out.println("线程:" + Thread.currentThread().getName() + "售出第" + (10000 - ticketNum) + "张票,还剩下" + --ticketNum + "张票");
}
}
}
/**
* 使用Lock来加锁
* 1. 创建可重入锁
* 2. 加锁
* 3. 业务操作
* 4. 解锁
*/
private final ReentrantLock lock = new ReentrantLock();
public void lockSale() {
lock.lock();
try {
if (ticketNum > 0) {
System.out.println("线程:" + Thread.currentThread().getName() + "售出第" + (10000 - ticketNum) + "张票,还剩下" + --ticketNum + "张票");
}
} finally {
lock.unlock();
}
}
}
1.4 线程间通信(线程交替进行)
-
创建资源类,在类中创建属性和操作方法
-
操作方法
- 判断是否有锁(this.wait())
- 业务处理
- 通知另一个线程 notify()
-
创建多个线程,调用资源类的操作方法
使用synchnorized
实现线程交替执行
this.wait()
线程等待
this.notifyAll()
线程唤醒
/**
* 1. 创建资源类,创建属性和操作方法
* 2. 判断、操作、通知
* 3. 创建多个线程调用操作方法
*/
public class AlternateThread {
public static void main(String[] args) {
AlternateTicket ticket = new AlternateTicket();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
ticket.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
ticket.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
class AlternateTicket {
private int num = 10;
public synchronized void incr() throws InterruptedException {
//判断
if (num > 10) {
this.wait();
}
//操作
num++;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
this.notifyAll();
}
public synchronized void decr() throws InterruptedException {
//判断
if (num <= 10) {
this.wait();
}
//操作
num--;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
this.notifyAll();
}
}
可以看到A和B交替执行且输出10、11
使用lock
实现线程交替执行
- 使用Lock.condition()对象进行线程等待和线程唤醒
lock.await()
线程等待lock.signalAll()
唤醒所有线程
/**
* 1. 创建资源类,创建属性和操作方法
* 2. 判断、操作、通知
* 3. 创建多个线程调用操作方法
*/
public class LockThread {
public static void main(String[] args) {
AlternateLockTicket ticket = new AlternateLockTicket();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
ticket.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
ticket.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
}
}
class AlternateLockTicket{
private int num=10;
//创建锁对象
private final Lock lock =new ReentrantLock();
Condition condition=lock.newCondition();
public void incr() throws InterruptedException {
lock.lock();
try{
//判断
if (num>10){
condition.await();
}
//操作
num++;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
condition.signalAll();
}finally {
lock.unlock();
}
}
public void decr() throws InterruptedException {
lock.lock();
try{
//判断
if (num<=10){
condition.await();
}
//操作
num--;
System.out.println(Thread.currentThread().getName() + ":" + num);
//通知
condition.signalAll();
}finally {
lock.unlock();
}
}
}