首页 > 编程语言 >JUC并发编程

JUC并发编程

时间:2022-11-19 11:48:16浏览次数:36  
标签:JUC Thread lock void 编程 number 并发 new public


线程和进程


进程:一个程序

一个进程往往可以包含多个线程,至少包含一个

线程:

对于java而言:Thread,Runnable,Callable

java不可以开启线程

并发(多个线程操作同一个资源)

CPU一核

并行(多人一起行走)

CPU多核,多个线程可以同是执行,线程池

//获取CPU的核数
System.out.println(Runtime.getRuntime().availableProcessors());

并发编程的本质:充分利用CPU的资源

线程的六个状态

 //新生
NEW
//运行
RUNNABLE
//阻塞
BLOCKED
//等待,死死地等
WAITING
//超时等待
TIMED WAITING
//终止
TERMINATEO

wite/sleep的区别

1、来自不同的类

wait——Object

sleep——Thread

2、关于锁的释放

wite会释放,sleep不会释放

3、使用的范围不同

wite:必须同步在代码块中

sleep:可以在任何地方用

4、是否捕获异常

wite不需要捕获异常

sleep必须捕获异常


lock锁


    • 传统:synchronized
//线程是一个单独的资源类,没有任何附属的操作
public class saleTicket {
    public static void main(String[] args){
       //并发、多线程操作同一个资源类,把资源类丢进线程里
        Ticket ticket=new Ticket();
        Ticket ticket2=new Ticket();
        //@FunctionalInterface 函数式接口
        //lambda表达式 (参数)->{代码}
        new Thread(()->{
            for(int i=1;i<50;i++){
            ticket.sale();}
            },"A").start();
        new Thread(()->{
            for(int i=0;i<50;i++){
            ticket.sale();}
            },"B").start();
        new Thread(()->{
            for(int i=0;i<50;i++){
            ticket.sale();}
            },"C").start();
    }
}
class Ticket{
    //属性、方法
    private int number=50;
    //synchronized 本质:队列,排队
    public synchronized void sale(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+
                    "卖出了"+(number--)+"票,剩余:"+number+"张");
        }
    }
}
    • Lock接口

 

公平锁:十分公平,先来后到

非公平锁:不公平,可以插队(默认

//lock三部曲
//1、new ReentrantLock();
//2、lock.lock();//加锁
//3、finally=>lock.unlock();//解锁
class Ticket2{
    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();//解锁
        }
    }
}

Synchornized和look的区别

      • Synchornized是内置的关键字,look是一个java类
      • Synchornized无法判断获取锁的状态,lock可以判断是否获取了锁
      • Synchornized会自动释放锁,lock必须手动释放锁,否则死锁
      • Synchornized线程一(获得锁,阻塞),线程二(等待)lock就不一定等待下去
      • Synchornized是可重入锁,不可以中断,非公平。Lock可重入锁,可以判断,非公平(可以自己设置)
      • Synchornized审核锁少量的代码同步问题,Lock适合锁大量的同步代码

生产者和消费者问题


Synchornized版

public class PC {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"D").start();
    }
}
class Data {
    private int number = 0;
    public synchronized void increment() {
        if (number > 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        this.notifyAll();
    }
    public synchronized void decrement() {
        if (number <= 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        this.notifyAll();
    }
}

 

当线程大于两个时便可能存在虚假唤醒的情况:因为使用的是if,执行完if内的内容唤醒后便会继续执行后续代码而不会再次判断等待条件, 换句话说,等待应该总是出现在循环中的

public class PC {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"D").start();
    }
}
class Data {
    private int number = 0;
    public synchronized void increment() {
        while (number > 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        this.notifyAll();
    }
    public synchronized void decrement() {
        while (number <= 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        this.notifyAll();
    }
}

Lock版

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PC {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.decrement();
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data.increment();
            }
        },"D").start();
    }
}
class Data {
    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();
    public void increment() {
        lock.lock();
        try {
            while (number > 0) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
    public void decrement() {
        lock.lock();
        try {
            while (number <= 0) {
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "=>" + number);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

condition实现精准通知唤醒


public class Demo05 {
public static void main(String[] args) {
Data01 data01 = new Data01();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data01.A();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data01.B();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data01.C();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
}
}


// 判断等待,业务,通知
//A执行完调用B,B执行完调用C,C执行完调用A
class Data01 {
private int num = 1;// 1A 2B 3C
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();


public void A() throws InterruptedException {
lock.lock();
try {
// 业务代码,判断=>执行=>通知!
while (num!=1){
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>AAAAA");
num = 2;
// 唤醒指定的线程,B
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void B() throws InterruptedException {
lock.lock();
try {
while (num!=2){
condition2.await();
}
num = 3;
System.out.println(Thread.currentThread().getName()+"=>BBBBB");
// 唤醒指定的线程,C
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void C() throws InterruptedException {
lock.lock();
try {
while (num!=3){
condition3.await();
}
num = 1;
System.out.println(Thread.currentThread().getName()+"=>CCCCC");
// 唤醒指定的线程,A
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

 


8锁现象


synchronized 锁的对象是方法的调用者

static方法类一加载就有了,锁的是class模板

 

 例1、

package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
 * 8锁,就是关于锁的8个问题
 * 1、标准情况下,两个线程先打印 发短信还是 先打印 打电话? 1/发短信  2/打电话
 * 1、sendSms延迟4秒,两个线程先打印 发短信还是 打电话? 1/发短信  2/打电话
 */.
public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        // 锁的存在
        new Thread(()->{
            phone.sendSms();
        },"A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone.call();
        },"B").start();
    }
}
class Phone{
    // synchronized 锁的对象是方法的调用者!、
    // 两个方法用的是同一个对象调用(同一个锁),谁先拿到锁谁执行!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);// 抱着锁睡眠
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
}
// 先执行 发短信,后执行打电话

 

例2、

package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
 * 3、 增加了一个普通方法后!先执行发短信还是Hello?// 普通方法
 * 4、 两个对象,两个同步方法, 发短信还是 打电话? // 打电话
 */
public class Test2  {
    public static void main(String[] args) {
        // 两个对象,两个调用者,两把锁!
        Phone2 phone1 = new Phone2();
        Phone2 phone2 = new Phone2();
        //锁的存在
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
        new Thread(()->{
            phone2.hello();
        },"C").start();
    }
}
class Phone2{
    // synchronized 锁的对象是方法的调用者!
    public synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    public synchronized void call(){
        System.out.println("打电话");
    }
    // 这里没有锁!不是同步方法,不受锁的影响
    public void hello(){
        System.out.println("hello");
    }
}
// 先执行打电话,接着执行hello,最后执行发短信

 

例3、

package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
 * 5、增加两个静态的同步方法,只有一个对象,先打印 发短信?打电话?
 * 6、两个对象!增加两个静态的同步方法, 先打印 发短信?打电话?
 */
public class Test3  {
    public static void main(String[] args) {
        // 两个对象的Class类模板只有一个,static,锁的是Class
        Phone3 phone1 = new Phone3();
        Phone3 phone2 = new Phone3();
        //锁的存在
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}
// Phone3唯一的一个 Class 对象
class Phone3{
    // synchronized 锁的对象是方法的调用者!
    // static 静态方法
    // 类一加载就有了!锁的是Class
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    } 
    public static synchronized void call(){
        System.out.println("打电话");
    }
}
// 先执行发短信,后执行打电话

 

例4、

package com.haust.lock8;
import java.util.concurrent.TimeUnit;
/**
 * 7、1个静态的同步方法,1个普通的同步方法 ,一个对象,先打印 发短信?打电话?
 * 8、1个静态的同步方法,1个普通的同步方法 ,两个对象,先打印 发短信?打电话?
 */
public class Test4  {
    public static void main(String[] args) {
        // 两个对象的Class类模板只有一个,static,锁的是Class
        Phone4 phone1 = new Phone4();
        Phone4 phone2 = new Phone4();
        //锁的存在
        new Thread(()->{
            phone1.sendSms();
        },"A").start();
        // 捕获
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            phone2.call();
        },"B").start();
    }
}
// Phone3唯一的一个 Class 对象
class Phone4{
    // 静态的同步方法 锁的是 Class 类模板
    public static synchronized void sendSms(){
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("发短信");
    }
    // 普通的同步方法  锁的调用者(对象),二者锁的对象不同,所以不需要等待
    public synchronized void call(){
        System.out.println("打电话");
    }
}
// 7/8 两种情况下,都是先执行打电话,后执行发短信,因为二者锁的对象不同,
// 静态同步方法锁的是Class类模板,普通同步方法锁的是实例化的对象,
// 所以不用等待前者解锁后 后者才能执行,而是两者并行执行,因为发短信休眠4s
// 所以打电话先执行。

小结

  • new this 具体的一个手机
  • static Class 唯一的一个模板

标签:JUC,Thread,lock,void,编程,number,并发,new,public
From: https://www.cnblogs.com/hinima/p/16903629.html

相关文章

  • 14.多线程并发在电商系统下的追本溯源(1)
                                                         ......
  • 函数式编程
    函数式编程函数是一等公民,函数式的思想来源于数学运算,而柯里化的操作可以将多参函数转为单参函数,而单参函数一般希望是纯函数(即不存在副作用的函数),可以实现f(g(x))这样......
  • Golang学习之路6-goroutine并发
    @目录前言一、goroutine用法二、goroutine循环三、goroutine提前退出四、goroutine双向管道五、goroutine单向管道六、监听管道如下图,可以看到当我们监听到有写入数据时会......
  • 并发编程(部分讲解)
    同步、异步、阻塞、非阻塞概念前言在实际的开发中,经常会听到同步,异步,阻塞,非阻塞这些编程概念,每次遇到的时候都会蒙圈,尤其是在一些场景下同步与阻塞,异步与非阻塞感觉没啥......
  • 并发编程
    并发编程同步与异步用来表达任务的提交方式同步提交完任务之后原地等待任务的返回结果期间不做任何事可靠任务序列异步提交完任务后不等待任务的返回结果直接去......
  • 并发编程
    内容概要并发编程理论与操作系统发展史多道技术近程理论及调度算法内容概要同步与异步阻塞与非阻塞创建进程的两种方式进程join方法进程间数据隔......
  • 网络编程与并发
    今日内容同步与异步用来表达任务的提交方式同步 提交完任务之后原地等待人物的返回结果期间不做任何事异步 提交完任务之后不原地等待任务的返回结果直接去做其......
  • 进入python的世界_day34_网络编程——同步与异步、进程、消息队列、互斥锁
    一、同步与异步、阻塞与非阻塞1.同步与异步介绍​ 一种方式,可以用来表示提交任务方提交任务后的行为同步:好比去办车牌的时候,提交了资料就呆在大厅一动不动,等着审核结果......
  • 08.大促高并发系统下JVM如何调优指导(4)
                                                         ......
  • 网络并发1
    今日内容详细同步与异步用来表达任务的提交方式同步 提交完任务之后原地等待任务的返回结果期间不做任何事异步 提交完任务之后不原地等待任务的返回结果直接去做......