2022.8.21 JUC
作者:互联网
1、什么是JUC
1、什么是juc(学习方法:官方文档+源码)
JUC —— (java.util.concurrent)是一个包名的缩写,java工具类下的一个并发功能的包。 该包下存放的均为多线程相关类,
Runnable 没有返回值、效率相比入 Callable相对较低,但callable可以返回结果,也可以抛出异常,两者都属于juc里面,Callable接口类似于Rurnable。然而,Runnable不返回结果,也不能抛出被检查的异常。
所以比起runable来说,callable有以下特点: 1、有返回值 2、可以抛出异常 3、方法不同,run(),call()
2、进程和线程回顾
进程:一个程序,QQ.exe Music.exe程序的线程的集合;
一个进程往往可以包含多个线程,至少包含一个!
Java默认有几个线程?最少2个,mian、GC
举例说明:开了一个进程Typora(开启进程),写字(一个线程),自动保存(又一个线程线程)
对于Java而言调用多线程的方法:Thread、Runnable(静态代理)、Callable(静态代理)
java真的可以开启线程嘛?(面试题)
不行,因为开启线程需要调用start0(),这是个本地方法,使用的是底层c++,java无法操作硬件
并发、并行:
-
并发(多线程操作同一个资源)
-
CPU一核,模拟出来多条线程,天下武功,唯快不破,快速交替
-
-
并行(多个人一起行走)
-
CPU多核,多个线程可以同时执行,线程池
-
新建一个maven项目
package com.xing.demo01;
public class Test1 {
public static void main(String[] args) {
//获取cpu核数
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
并发编程的本质:充分利用CPU的资源
线程有几个状态:
java有6个状态,操作系统有5个
public enum State {
//新生
NEW,
//运行
RUNNABLE,
//阻塞
BLOCKED,
//无限期等待
WAITING,
//限时等待
TIMED_WAITING,
//结束
TERMINATED;
}
java的Thread.State源码中操作系统的五个状态:初始状态(NEW) ,可运行状态(READY),运行状态(RUNNING) ,等待状态(WAITING) ,终止状态(TERMINATED)。
区别: 当线程调用阻塞式 API时,进程(线程)进入等待状态,这里指的是操作系统层面的。从 JVM层面来说,Java线程仍然处于 RUNNABLE 状态。JVM 并不关心操作系统线程的实际状态,从 JVM 看来,等待CPU使用权(操作系统状态为可运行态)与等待 I/O(操作系统处于等待状态)没有区别,都是在等待某种资源,所以都归入RUNNABLE 状态
wait/sleep区别:
1、来自不同的类
-
wait=>object
-
sleep=>Thread
常用的休眠方法:使用java.util.concurrent里的TimeUnit
-
TimeUnit.SECONDS.sleep(1);//睡1秒
-
TimeUnit.DAYS.sleep(2);//睡2天
2、关于锁的释放
-
wait 会释放锁
-
sleep睡觉了,抱着锁睡觉,不会释放!
3、使用的范围不同
-
wait:必须在同步代码块。
-
sleep:可在任何地方睡。
#即有synchronized修饰符修饰的语句块,被该关键词修饰的语句块,将加上内置锁。实现同步。 例:synchronized(Object o ){}
4、是否需要捕获异常,两者都需要捕获异常
-
wait:不需要捕获异常
-
sleep:必须要捕获异常
线程都会有中断异常
3、Lock锁
1、传统的Synchronized
没有使用Synchronized前:
package com.xing.demo01;
/**
* @Description:
* 线程就是一个资源类,没有任何附属的操作,包括属性、方法
**/
public class SaleTicket {
public static void main(String[] args) {
//并发:多个线程操作同一个资源类
Ticket1 ticket =new Ticket1();
/* new Thread(new Runnable() {
@Override
public void run() {
}
});*/
// 删掉了new Runnable() {
// @Override
// public void run 还有一个 } 然后加上->
/* new Thread((写方法的参数)->{写代码});*/
//线程1 A为线程名
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"A").start();
//线程2
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"B").start();
//线程3
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"C").start();
}
}
//资源类
class Ticket1 {
private int ticket=500;
private int leftTicket=1;
public void sellTicket(){
if (ticket>0)
System.out.println(Thread.currentThread().getName()+"卖出了第"+(leftTicket++)+"张票"+"剩下:"+(ticket--)+"张票");
}
}
会造成数据紊乱
使用Synchronized:
package com.xing.demo01;
/**
* @Description:
* 线程就是一个资源类,没有任何附属的操作,包括属性、方法
**/
public class SaleTicket {
public static void main(String[] args) {
//并发:多个线程操作同一个资源类
Ticket1 ticket =new Ticket1();
/* new Thread(new Runnable() {
@Override
public void run() {
}
});*/
// 删掉了new Runnable() {
// @Override
// public void run 还有一个 } 然后加上->
/* new Thread((写方法的参数)->{写代码});*/
//线程1 A为线程名
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"A").start();
//线程2
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"B").start();
//线程3
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"C").start();
}
}
//资源类
class Ticket1 {
private int ticket=500;
private int leftTicket=1;
//加上synchronized 本质排队 线程每次执行前会得到一把锁,本次执行完释放锁
public synchronized void sellTicket(){
if (ticket>0)
System.out.println(Thread.currentThread().getName()+"卖出了第"+(leftTicket++)+"张票"+"剩下:"+(ticket--)+"张票");
}
}
2、Lock锁
属于JUC包下,是一个接口,实现类有读、写锁和可重入锁(reentrantlock)
package com.xing.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Description: 与使用synchronized的效果一样
* 线程就是一个资源类,没有任何附属的操作,包括属性、方法
**/
public class SaleTicket {
public static void main(String[] args) {
//并发:多个线程操作同一个资源类
Ticket1 ticket = new Ticket1();
//线程1 A为线程名
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"A").start();
//线程2
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"B").start();
//线程3
new Thread(()->{
for (int i=1;i<60;i++)
ticket.sellTicket();
},"C").start();
}
}
//资源类
class Ticket1 {
private int ticket = 50;
private int leftTicket = 1;
// 1、Lock下的实现类ReentrantLock
Lock lock = new ReentrantLock();
public void sellTicket() {
//2、加锁
lock.lock();
//业务代码放入try catch中
try {
if (ticket > 0) {
ticket--;
leftTicket++;
System.out.println(Thread.currentThread() + "卖出了第" + (leftTicket) + "张票" + "剩下:" + ticket + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//3、解锁
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、生产者和消费者
Synchronized 版生产者和消费者问题
package com.xing.demo02;
import sun.awt.windows.ThemeReader;
/**
线程之间的通信问题:生产者和消费者问题
线程交替执行:A B操作同一个变量 num = 0
A num+1
B num-1
*/
public class SYProducers {
public static void main(String[] args) {
Date date = new Date();
//执行+1
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
//执行-1
new Thread(()->{
for (int i =0;i<10;i++){
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
//判断等待,业务,通知
class Date{//数字 资源类
private int number = 0;
//+1 生产者
public synchronized void increment() throws InterruptedException {
if (number !=0){
//等待
this.wait();
}
number++;
//通知其他线程,我+1完毕
System.out.println(Thread.currentThread().getName() +"=>" + number);
this.notifyAll();
}
//-1 消费者
public synchronized void decrement() throws InterruptedException {
if (number == 0){
//等待
this.wait();
}
number --;
//通知其他线程,我-1完毕
System.out.println(Thread.currentThread().getName() +"=>" + number);
this.notifyAll();
}
}
问题存在,A B C D 4 个线程! 虚假唤醒
解决方法:用while代替if
if判断改为while判断
package com.xing.demo02;
import sun.awt.windows.ThemeReader;
/**
线程之间的通信问题:生产者和消费者问题
线程交替执行:A B操作同一个变量 num = 0
A num+1
B num-1
*/
public class SYProducers {
public static void main(String[] args) {
Date date = new Date();
//执行+1
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
//执行-1
new Thread(()->{
for (int i =0;i<10;i++){
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断等待,业务,通知
class Date{//数字 资源类
private int number = 0;
//+1
/*
假设 number此时等于1,即已经被生产了产品
如果这里用的是if判断,如果此时A,C两个生产者线程争夺increment()方法执行权
假设A拿到执行权,经过判断number!=0成立,则A.wait()开始等待(wait()会释放锁),然后C试图去执行生产方法,
但依然判断number!=0成立,则C.wait()开始等待(wait()会释放锁)
碰巧这时候消费者线程B/D去消费了一个产品,使number=0然后,B/D消费完后调用this.notifyAll();
这时候2个等待中的生产者线程继续生产产品,而此时number++ 执行了2次
同理,重复上述过程,生产者线程继续wait()等待,消费者调用this.notifyAll();
然后生产者继续超前生产,最终导致‘产能过剩’,即number大于1
if(number != 0){
// 等待
this.wait();
}*/
public synchronized void increment() throws InterruptedException {
while (number !=0){
//等待
this.wait();
}
number++;
//通知其他线程,我+1完毕
System.out.println(Thread.currentThread().getName() +"=>" + number);
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number == 0){
//等待
this.wait();
}
number --;
//通知其他线程,我-1完毕
System.out.println(Thread.currentThread().getName() +"=>" + number);
this.notifyAll();
}
}
JUC版的生产者和消费者问题
package com.xing.demo02;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LOCKProducers {
public static void main(String[] args) {
Date2 date = new Date2();
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
//执行-1
new Thread(()->{
for (int i =0;i<10;i++){
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i =0; i<10;i++){
try {
date.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
}
}
//判断等待,业务,通知
class Date2 {//数字 资源类
private int number = 0;
//+1
Lock lock = new ReentrantLock();
//上面四个线程用一个同步监视器
Condition condition = lock.newCondition();
public void increment() throws InterruptedException {
//condition.await();//等待
//condition.signalAll();//唤醒全部
lock.lock();
try{
// 业务代码
while (number != 0) {
//等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
//-1
public void decrement() throws InterruptedException {
lock.lock();
try{
while (number == 0) {
//等待
condition.await();
}
number--;
//通知其他线程,我-1完毕
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
Condition 精准的通知和唤醒线程,有序执行线程
package com.xing.demo02;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* A执行完调用B,B执行完调用C,C执行完调用A
*/
public class C {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(()->{
for (int i =0; i< 10; i++){
data3.printA();
}
},"A").start();
new Thread(()->{
for (int i =0; i< 10; i++){
data3.printB();
}
},"B").start();
new Thread(()->{
for (int i =0; i< 10; i++){
data3.printC();
}
},"C").start();
}
}
class Data3{//资源lock
private Lock lock = new ReentrantLock();
//相当于给每个线程都设置一个同步监视器
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1;// 1:A执行 2:B执行 3:C执行
//三个方法用的同一把锁lock(),每次只能进入一个线程
public void printA(){
lock.lock();
try{
while(number != 1){
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName() + " => A");
//唤醒指定的condition2监视器
condition2.signal();
number = 2;
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try{
//业务,判断,执行,通知
while(number != 2){
condition2.await();
}
System.out.println(Thread.currentThread().getName() + " => B");
condition3.signal();
number = 3;
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try{
while(number != 3){
condition3.await();
}
System.out.println(Thread.currentThread().getName() + " => C");
condition1.signal();
number
= 1;
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
//用于生产线:下单->支付操作->交易->物流
}
标签:JUC,21,Thread,int,number,线程,2022.8,new,public 来源: https://www.cnblogs.com/shanzha/p/16610923.html