ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2022.8.21 JUC

2022-08-21 21:31:15  阅读:166  来源: 互联网

标签:JUC 21 Thread int number 线程 2022.8 new public


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有