JUC并发编程一:了解与回顾

什么是JUC

JUC,即java.util.concurrent包的缩写,是java原生的并发包和一些常用的工具类。
在这里插入图片描述

回顾多线程

在多线程阶段我们利用Thread和Runnable或者Callable来启动多线程
Runnable没有返回值,效率比Callable低,在企业中Callable用的相对较多

线程和进程

进程:一个程序
线程:一个程序包含多个线程,指具体执行的任务
Java默认有两个线程:main和GC
Java不能真的启动线程,调用的是本地方法,也就是底层的c++,java无法直接操作硬件,因为它是运行在虚拟机上的

并发和并行

并发:多线程操作一个资源(让线程快速交替执行)
并行:多线程同时执行

使用多线程或者并发编程的目的:提高效率,让CPU一直工作,达到最高的处理性能。

线程的状态
  1. 新建(NEW):新创建了一个线程对象。

  2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。

  3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。

  4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:

(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
(三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

  1. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
wait和sleep的区别

1.来自不同的类
wait:Object
sleep:Thread
企业不用sleep用TimeUnit
2.关于锁的释放
wait:释放锁
sleep:不会释放
3.使用的范围
wait:必须在同步代码块中使用
sleep:可以在任何地方使用
4.是否需要捕获异常
wait:不需要
sleep:必须需要捕获

lock和synchronized的区别

举一个卖票的例子
用synchronized

package com.www.demo01;

public class SaleTicket {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                ticket.sale();
            }
        },"C").start();
    }
}

class Ticket{
    private int number = 1;
    public synchronized void sale(){
        if (number <= 30){
            System.out.println(Thread.currentThread().getName() + "卖出了第" + number++
            + "张票,还剩余" + (31 - number) + "张票");
        }
    }
}

用lock

package com.www.demo02;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SaleTickets {
    public static void main(String[] args) {
        Tickets tickets = new Tickets();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                tickets.sale();
            }
        },"D").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                tickets.sale();
            }
        },"E").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                tickets.sale();
            }
        },"F").start();
    }
}

class Tickets{
    private int number = 1;
    //1.创建lock锁
    Lock lock = new ReentrantLock();
    public void sale(){
        //2.加锁
        lock.lock();
        try {
            //业务代码
            if (number <= 30){
                System.out.println(Thread.currentThread().getName() + "卖出了第" + number++
                        + "张票,还剩余" + (31 - number) + "张票");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //3.解锁
            lock.unlock();
        }
    }
}

区别

1.Synchronized是个关键字Lock是个类
2.Synchronized无法判断获取锁的状态,Lock可以判断
3.Synchronized会自动释放锁,Lock需要手动释放
4.Synchronized如果一个线程阻塞,另一个线程会一直等待。Lock则不会
5.Synchronized可重入锁,不可以中断的非公平锁,Lock可重入锁,可以判断锁,公平与否可以自行设置
6.Synchronized适合锁少量,Lock适合大量锁

线程之间的通信

四个线程操作同一个变量

package com.www.demo03;

public class Procedure {
    public static void main(String[] args) {
        Test test = new Test();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    test.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    test.del();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    test.del();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"C").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    test.del();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"D").start();
    }
}
class Test{
    private int number = 0;
    public synchronized void add() throws InterruptedException {
    //这里把if换成while是防止虚假唤醒
        while (number != 0){
            //线程等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        //唤醒其他线程
        this.notifyAll();
    }

    public synchronized void del() throws InterruptedException {
    //这里把if换成while是防止虚假唤醒
        while (number == 0){
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "=>" + number);
        this.notifyAll();
    }
}

JUC

package com.www.demo05;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Pro {
    public static void main(String[] args) {
        Test01 test01 = new Test01();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                test01.A();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                test01.B();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                test01.C();
            }
        },"C").start();
    }
}
class Test01{
    Lock lock = new ReentrantLock();
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();
    private int number = 1;
    public void A(){
        lock.lock();
       try {
           while (number != 1){
               condition1.await();
           }
           number = 2;
           System.out.println(Thread.currentThread().getName() + "=>" + "AAAAA");
           condition2.signal();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }finally {
           lock.unlock();
       }
    }
    public void B(){
        lock.lock();
        try {
            while (number != 2){
                condition2.await();
            }
            number = 3;
            System.out.println(Thread.currentThread().getName() + "=>" + "BBBBB");
            condition3.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void C(){
        lock.lock();
        try {
            while (number != 3){
                condition3.await();
            }
            number = 1;
            System.out.println(Thread.currentThread().getName() + "=>" + "CCCCC");
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

使用conditional的优势:可以精确的通知和唤醒线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值