JUC并发编程
01、JUC基础
JUC实际上就是我们对于jdk中java.util .concurrent 工具包的简称。这个包下都是Java处理线程相关的类。
-
进程(Process)
计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的 描述,进程是程序的实体。 -
并发和并行
串行:即表示所有任务都是按先后顺序进行。串行是一次只能取的一个任务,并执行这个任务。
并行:
- 一组程序按独立异步的速度执行,无论从微观还是宏观,程序都是一起执行的。对比地
- 并行模式相当于将长长的一条队列,划分成了多条短队列,所以并行缩短了任务队列的长度。
- 并行的效率,一方面受多进程/线程编码的好坏的影响,另一方面也受硬件角度上的CPU的影响。
并发:
- 并发指的是多个程序可以同时运行的一种现象。
- 并发是指:在同一个时间段内,两个或多个程序执行,有时间上的重叠(宏观上是同时,微观上仍是顺序执行)。
- 并发的重点在于它是一种现象,并发描述的是多进程同时运行的现象。但真正意义上,一个单核心CPU任一时刻都只能运行一个线程。所以此处的"同时运行"表示的不是真的同一时刻有多个线程运行的现象(这是并行的概念),而是提供了一种功能让用户看来多个程序同时运行起来了,但实际上这些程序中的进程不是一直霸占 CPU 的,而是根据CPU的调度,执行一会儿停一会儿。
- 例子
- 并行:多个任务一起执行,之后再汇总
例子:电饭煲煮饭、用锅炒菜,两个事情一起进行, - 并发:即同一时刻多个线程在访问同一个资源,多个线程对一个点
例子:秒杀活动、12306抢回家的票啦、抢演唱会的票…
JAVA固定有两个线程分别为:main和GC
java无法开启线程
wait -》Object
sleep-》Thread
wait可以释放锁
sleep不会释放
wait不需要捕获异常
sleep可以捕获异常
02、线程同步锁
Lock 传统的Synchronized
线程就是一个单独的资源类,没有任何附属的操作
public class Runable {
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
Ticket ticket = new Ticket();
int a = 30;
new Thread(()->{
for (int i = 0; i < a; i++) {
System.out.print("老张" );
ticket.getTicket();
}
}).start();
new Thread(()->{
for (int i = 0; i < a; i++) {
System.out.print("老王" );
ticket.getTicket();
}
}).start();
new Thread(()->{
for (int i = 0; i < a; i++) {
System.out.print("小刘" );
ticket.getTicket();
}
}).start();
}
}
class Ticket {
private int amount = 50;
public void getTicket(){
if(amount>0){
System.out.println("拿到了第"+ amount-- + ", 还剩下 " + amount + "张票");
}
}
}
线程不安全
public synchronized void getTicket(){
if(amount>0){
System.out.println("拿到了第"+ amount-- + ", 还剩下 " + amount + "张票");
}
}
Lock锁
生产者-消费者
public class ProCon {
public static void main(String[] args) {
Data data = new Data();
int len = 10;
new Thread(()->{
for (int i = 0; i < len; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(()->{
for (int i = 0; i < len; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
class Data{
private int commodity = 1;
public synchronized void increment() throws InterruptedException {
while(commodity!=0){
this.wait();
}
commodity++;
System.out.println(Thread.currentThread().getName() + "->" + commodity);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while(commodity==0){
this.wait();
}
commodity--;
System.out.println(Thread.currentThread().getName() + "->" + commodity);
this.notifyAll();
}
}
-
虚假唤醒
线程可以被唤醒,但是不会通知、中断
所以等待总是出现在循环中 -
Lock版本的消费者和生产者
condition+lock取代synic+notify可以实现精准唤醒
八锁现象彻底理解锁
集合的安全问题
ConcurrentMap
countdownlatch
阻塞队列
FIFO
写:如果队列满了,阻塞等待
取:如果队列是空的,阻塞等待
BlockingQueue