一、前瞻
1、什么是JUC
java.util.concurrent包
2、线程与进程
一个进程往往包含多个线程
java默认有两个线程:main、GC(垃圾回收)
java真的可以开启线程吗?
不可以,底层使用C++,java无法直接操作硬件
1>线程六大状态
//新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//等待超时
TIMED_WAITING,
//终止
TERMINATED;
2>wait和sleep的区别
1、来自不同的类
wait–>Object
sleep–>Thread
2、wait会释放锁,sleep不会释放锁
3、使用范围不同
wait必须在同步代码块中使用
sleep可以在任何地方使用
3、并发与并行
并发即多线程操作同一个资源
单核CPU快速交替
并行即多个线程同时执行;线程池
并发变成的本质:充分利用CPU资源
二、Lock
1、传统的synchronized
package cn.biliball;
public class Test01 {
public static void main(String[] args) {
//获取CPU核数
//System.out.println(Runtime.getRuntime().availableProcessors());
final Ticket ticket=new Ticket();
new Thread(()->{
for(int i=0;i<40;i++)
ticket.sale();
},"A").start();
new Thread(() -> {
for(int i=0;i<40;i++)
ticket.sale();
},"B").start();
new Thread(() -> {
for(int i=0;i<40;i++)
ticket.sale();
},"C").start();
}
}
//资源类
class Ticket{
private int number=30;
public synchronized void sale(){
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"张票,剩余"+number+"张票。");
}
}
}
2、使用Lock
Lock的三个实现类
ReentrantLock()(重入锁)
ReentrantReadWriteLock.ReadLock()(读锁)
ReentrantReadWriteLock.WriteLock()(写锁)
公平锁:先来先执行
非公平锁:可以插队
java默认非公平锁,保证CPU利用率
package cn.biliball;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test02 {
public static void main(String[] args) {
//获取CPU核数
//System.out.println(Runtime.getRuntime().availableProcessors());
final Ticket02 ticket=new Ticket02();
new Thread(() -> {
for(int i=0;i<40;i++)
ticket.sale();
},"A").start();
new Thread(() -> {
for(int i=0;i<40;i++)
ticket.sale();
},"B").start();
new Thread(() -> {
for(int i=0;i<40;i++)
ticket.sale();
},"C").start();
}
}
//资源类
class Ticket02{
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();//解锁
}
}
}
3、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、生产者和消费者问题
面试的:单例模式、排序算法、生产者和消费者、死锁
package cn.biliball.pc;
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();
}
}
// 判断等待,业务,通知
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
//问题存在,A B C D 4 个线程! 虚假唤醒
//if 改为 while 判断
// 等待
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
// 通知其他线程,我-1完毕了
this.notifyAll();
}
}
如果有四个线程,会存在虚假唤醒的问题
将if换成while
5、JUC版的生产者与消费者问题
package cn.biliball.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class B {
public static void main(String[] args) {
Data02 data = new Data02();
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 Data02 {
// 数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//+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 (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public synchronized void decrement() throws InterruptedException {
lock.lock();
try {
while (number == 0) {
// 1
//问题存在,A B C D 4 个线程! 虚假唤醒
//if 改为 while 判断
// 等待
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);