首页 > 其他分享 >JUC

JUC

时间:2022-11-28 08:56:18浏览次数:30  
标签:JUC Thread lock void number 线程 public

JUC概述

JUC简介

  • 在Java中,线程部分是一个重点,本篇文章说的JUC也是关于线程的。JUC就是java.util.concurrent工具包的简称。这是一个处理线程的包,JDK1.5开始出现的。

进程与线程

  • 进程(Process)
    • 计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。
  • 线程(thread)
    • 操作系统能够进行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

  • 进程:值在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程———资源分配的最小单位
  • 线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程———程序执行的最小单位

线程的状态

  • 新建
  • 就绪
  • 运行
  • 阻塞
  • 结束

wait/sleep

  • sleep是Thread的静态方法,wait是Object的方法,任何对象实例都能调用
  • sleep不会释放锁,它也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)
  • 他们都可以被interrupthttps://www.bilibili.com/account/historyed方法中断

并发与并行

  • 并发
    • 同一时刻多个线程在访问统一资源,多个线程对一个点
  • 并行
    • 多项工作一起执行,之后再汇总

卖票

/**
 * 三个售票员 卖 30张票
 */
public class SaleTicket {
    public static void main(String[] args) {
        //线程类
        final Ticket ticket = new Ticket();

        /**
         * 使用匿名内部类实现Runnable接口
         */
        new Thread(new Runnable() {
            public void run() {
                while (ticket.getTicketCount() > 0){
                    ticket.sale();
                }
            }
        }, "售票员1").start();

        new Thread(new Runnable() {
            public void run() {
                while (ticket.getTicketCount() > 0){
                    ticket.sale();
                }
            }
        }, "售票员2").start();

        new Thread(new Runnable() {
            public void run() {
                while (ticket.getTicketCount() > 0){
                    ticket.sale();
                }
            }
        }, "售票员3").start();
    }
}


class Ticket{

    private int ticketCount = 30;

    public synchronized void sale(){
        if (ticketCount > 0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+(ticketCount--)+"张票,剩余"+ticketCount+"张票");
        }
    }

    public  int getTicketCount() {
        return ticketCount;
    }
}
  • 使用可重入锁(ReentrantLock)
class Ticket{
    private int ticketCount = 30;

    //可重入锁
    private Lock lock = new ReentrantLock();

    public void sale(){
        //加锁
        lock.lock();
        try {
            if (ticketCount > 0){
                System.out.println(Thread.currentThread().getName()+"卖出第"+(ticketCount--)+"张票,剩余"+ticketCount+"张票");
            }
        }finally {
            //解锁
            lock.unlock();
        }
    }

    public int getTicketCount() {
        return ticketCount;
    }
}

线程间的通信

生产者消费者通信

  • 现有两个线程,可以操作初始值为0的一个变量,实现一个线程对变脸加一,一个线程实现对变量减一,实现交替来5轮
//空调
class AirConditioner{
    //空调度数
    private int number = 0;
    //加一度
    public synchronized void increment() throws InterruptedException {
        //判断number是否为0,如果不为0则等待
        if (number != 0){
            this.wait();
        }
        //加一度
        number++;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //通知另一个线程可以减1了
        this.notifyAll();
    }
    //减一度
    public synchronized void decrement() throws InterruptedException {
        if (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();
    }
}

/**
 * 现在有两个线程,可以操作初始值为0的一个变量
 * 实现一个线程对变量加1,一个线程对该变量减1
 * 实现交替,来5轮
 */
public class ThreadWaitNotifyDemo {
    public static void main(String[] args) {
        //空调资源类
        AirConditioner airConditioner = new AirConditioner();

        //线程A每次加一,来10轮
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    airConditioner.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();

        //线程B每次减一,来10轮
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    airConditioner.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
    }
}
  • 控制台输出
A	1
B	0
A	1
B	0
A	1
B	0
A	1
B	0
A	1
B	0
  • 新增两个线程,两个线程加一,两个线程减一。则会出现虚假唤醒的情况
  • 例子:变量为0线程1判断通过则加一然后唤醒其他线程(此时应该唤醒减一的线程),唤醒了所有的线程,并且另一个加一的线程执行了,则变量变为2
  • 解决方法,使用while提换掉if,当被唤醒之后再进行判断是否执行
//空调
class AirConditioner{
    //空调度数
    private int number = 0;
    //加一度
    public synchronized void increment() throws InterruptedException {
        //判断number是否为0,如果不为0则等待
        while (number != 0){
            this.wait();
        }
        //加一度
        number++;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //通知另一个线程可以减1了
        this.notifyAll();
    }
    //减一度
    public synchronized void decrement() throws InterruptedException {
        while (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        this.notifyAll();
    }
}
  • 使用可重入锁ReentrantLock替换synchronized
//空调
class AirConditioner{
    //空调度数
    private int number = 0;

    //可重入锁
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    //加一度
    public void increment() throws InterruptedException {
        //加锁
        lock.lock();
        try{
            //判断number是否为0,如果不为0则等待
            while (number != 0){
                condition.await();
            }
            //加一度
            number++;
            System.out.println(Thread.currentThread().getName()+"\t"+number);
            //通知另一个线程可以减1了
            condition.signal();
        }finally {
            lock.unlock();
        }
    }
    //减一度
    public synchronized void decrement() throws InterruptedException {
        //加锁
        lock.lock();
        try{
            //判断number是否为0,如果为0则等待
            while (number == 0){
                condition.await();
            }
            //加一度
            number--;
            System.out.println(Thread.currentThread().getName()+"\t"+number);
            //通知另一个线程可以加1了
            condition.signal();
        }finally {
            lock.unlock();
        }
    }
}

精确通知顺序访问

  • 案例
    • 多线程之间按顺序,实现A-B-C
    • A打印5次,B打印10次,C打印15次,来10轮
class ShareResource{
    private int number = 1;  //1 A打印 2 B打印 3 C打印
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC = lock.newCondition();


    public void print5(){
        lock.lock();
        try{
            while (number != 1){
                conditionA.await();
            }
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+(i+1));
            }
            //将标志位改为2B打印10次
            number = 2;
            //唤醒conditionB 
            conditionB.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print10(){
        lock.lock();
        try{
            while (number != 2){
                conditionB.await();
            }
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+(i+1));
            }
            //将标志位改为2B打印10次
            number = 3;
            //唤醒conditionC
            conditionC.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print15(){
        lock.lock();
        try{
            while (number != 3){
                conditionC.await();
            }
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName()+"\t"+(i+1));
            }
            //将标志位改为2B打印10次
            number = 1;
            //唤醒conditionA
            conditionA.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}


public class ThreadOrderAccess {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                shareResource.print5();
            }
        },"A").start();

        new Thread(()-> {
            for (int i = 0; i < 10; i++) {
                shareResource.print10();
            }
        },"B").start();

        new Thread(()-> {
            for (int i = 0; i < 10; i++) {
                shareResource.print15();
            }
        },"C").start();
    }
}

标签:JUC,Thread,lock,void,number,线程,public
From: https://www.cnblogs.com/blackyoumo/p/16923743.html

相关文章

  • JUC并发编程
    线程和进程进程:一个程序一个进程往往可以包含多个线程,至少包含一个线程:对于java而言:Thread,Runnable,Callablejava不可以开启线程并发(多个线程操作同一个资源)CPU一......
  • JUC并发编程(2)
    cpu密集型:几核就设置几,可以保持cpu的效率最高io密集型:设置大于判断你程序中十分耗io资源的线程ForkJoin:分而治之和工作窃取算法Future:异步回调:比如我i请求阻塞线程两秒......
  • JUC学习笔记——并发工具线程池
    JUC学习笔记——并发工具线程池在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的并发工具线程池我们会分为以下几部分进行介绍:线程池介绍自定义线程池模......
  • JUC并发编程
    1并发:多个线程操作同一个资源在cou一核的时候,多个线程模拟并发2并行cpu多核的时候,多个线程同时执行3并发编程的本质:充分利用cpu的资源4wait和sleep的区别:wait来自o......
  • nunjucks模板语法
    循环语句server.jsconstKoa=require("koa");//引入koa构造函数constapp=newKoa();//创建应用constviews=require("koa-views");//引入koa-viewsconstnunju......
  • Nunjucks模板入门
    概述安装nunjucks代码实现server.jsconstKoa=require("koa");//引入koa构造函数constapp=newKoa();//创建应用constviews=require("koa-views");//引入k......
  • JUC学习笔记——共享模型之不可变
    JUC学习笔记——共享模型之不可变在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的不可变内容我们会分为以下几部分进行介绍:不可变案例不可变设计模式之......
  • 010_JUC简介
    目录什么是JUC回顾多线程线程和进程查看源码newThread().start()并发和并行查看CPU内核和逻辑处理器数量线程的状态wait和sleep的区别什么是JUC:::infojava.util.con......
  • 060_JUC常用辅助类
    目录CountDownLatch倒计时计数器,减法计数器演示代码CyclicBarrier加法计数器演示代码Semaphore计数信号量演示代码CountDownLatch倒计时计数器,减法计数器演示代码......
  • JUC学习笔记——共享模型之无锁
    JUC学习笔记——共享模型之无锁在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的无锁我们会分为以下几部分进行介绍:无锁操作CAS与Volatile原子类型原理......