【狂神说java juc 20200219 01篇】线程和进程,线程6状态,Lock锁,生产者消费者,Condition

1. 大纲

  • lock锁
  • 生产者 消费者
  • 锁的现象
  • 线程类 不安全
  • Callable
  • CountDownLatch
    • CyclicBarrier
    • Semaphore
  • 读写锁
  • 阻塞队列
  • 线程池
  • 四大函数式接口
  • Stream流式计算
  • 分支合并
  • 异步回调
  • JMM
  • volatile
  • 单例模式
  • CAS
  • 原子引入
  • 可重入锁
    • 公平锁 非公平锁
    • 自旋锁
    • 死锁
Latch
英
/lætʃ/
美
/lætʃ/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
门闩,窗闩;<英>碰锁,碰簧锁;(电子)门闩线路,锁存器
v.
闩上(门),用弹簧锁锁住(门等);(电子)(装置)状态恒定;占有,抓住

barrier
英
/ˈbæriə(r)/
美
/ˈbæriər/
n.
障碍,壁垒;障碍物,关卡;分界线,屏障;大关,界限

Semaphore
英
/ˈseməfɔː(r)/
美
/ˈseməfɔːr/
(计)信号量

signal
信号,暗号;标志,预示;(尤指铁路和公路上的)指示灯,信号灯;(无线电、电视等的)讯号,信号;起因,导火线;(桥牌)信号;(传递的)信息
v.
发信号,示意;标志,预示;告知,表示;(车辆转方向时)打灯示意
adj.
重大的,显要的;作为信号的

volatile
adj.
易变的,动荡不定的,反复无常的;(情绪)易变的,易怒的,突然发作的;(液体或固体)易挥发的,易气化的;(计算机内存)易失的
Cyclic
英
/ˈsaɪklɪk/
美
/ˈsaɪklɪk/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
adj.
环的;循环的;周期的

cycl
pref.
圆形的;与自行车有关的;环状的(用于元音前,同 cyclo-)

cycle
n.
自行车,摩托车;循环,周期;组诗,组歌;整套,系列;自行车骑行;一段时间
v.
骑自行车;循环

bicycle
n.
单车,自行车
v.
骑自行车

所属的三个包

java.util.concurrent

  • 实用程序类通常在并发编程中很有用。
  • Callable

java.util.concurrent.atomic

  • 一个小型工具包,支持单个变量上的无锁线程安全编程。

java.util.concurrent.locks

  • 接口和类提供了一个框架,用于锁定和等待与内置同步和监视器不同的条件。
  • Lock类

java.util.function

  • 功能界面提供了lambda表达式和方法引用的目标类型。

concurrent下

util.concurrent

  • Blocking Queue

    • Deque
  • Callable

  • Completable Future

  • ConcurrentHashMap

    • LinkedQueue
  • CopyOnWriteArrayList

    • ArraySet
  • CountDownLatch

  • CyclicBarrier

  • DelayQueue

  • Executor

    • Executors
  • Future

    • FutureTask
  • LinkedBlockingDeque

    • Queue
  • Runnable Future

  • Scheduled Future

    • Scheduled Executor Serive
    • Schedule Thread Pool Executor
  • Semaphore

  • ThreadPoolExecutor

  • TimeUnit

deque
英
/dek/
美
/dɛk/

n.
双端队列;双队列

atomic下

concurrent.atomic

  • Automic Boolean
    • Integer
    • IntegerArray
    • Long
    • LongArray
    • Reference
  • DoubleAccumulator
    • Double Addre
  • Long Accumulator
    • Long Adder
  • Stringped 64

locks下,三大接口

concurrent.locks

  • AbstractOwnableSynchronizer

  • AbstractQueuedLongSynchronizer

  • AbstractQueuedSynchronizer

  • Condition 接口

  • Lock 接口

    • LockSupport
  • ReadWriteLock 接口

    • ReentrantLock
    • ReenTrantReadWriteLock
    • StampedLock

2. 线程和进程

  • Call able
  • Runnable
		<dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
        </dependency>

java默认有两个线程:

  • main ,GC

  • 线程:开了一个进程Typora,写字,自动保存(线程负责)

start()源码

  • java真的可以开启线程吗?不可以
  • 底层是:本地方法,调用底层c++,java运行在虚拟机之上,无法直接操作硬件,由c++开启多线程
new Thread(new MyThread(lockA, lockB), "T1").start();
public synchronized void start() {

        group.add(this);

        boolean started = false;

            start0();
            started = true;

    	if (!started) {
        	group.threadStartFailed(this);
    	}
    }

	//本地方法
    private native void start0();

3. 线程回顾

		//获取cpu的核数
        //cpu密集型,io密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
processors
/prɔ:'sesəz/
(计)处理器,处理机;加工者,加工物(processor 的复数)

process
n.
步骤,程序;(自然或偶然的)变化过程;(为达到某目标的)过程,进程;制作方法,加工方法;<法律>传票;(生,剖)端突,突起
adj.
(印刷)三原色的,三色版的; 经过特殊加工的;照相板的
v.
(用化学物品或机器)处理,加工;审核,受理(正式文件或请求);(计算机)处理(数据);冲洗(照片);加工(食品);<正式>列队行进;把(头发)弄成直发

线程6状态

public enum State {
//就绪
NEW,
    
//运行
RUNNABLE,
    
//阻塞
BLOCKED,
    
//等待,死等
WAITING,
    
//超时等待
TIMED_WAITING,
    
//终止 ter mi na ted
TERMINATED;
}

wait与sleep

  1. 来自不同的类
    wait=》Object
    sleep=》Thread
  2. wait释放锁,sleep抱着锁睡觉
  3. 使用的范围是不同的。wait必须在同步代码快中,sleep可以在任何地方睡觉
  4. wait不需要捕获异常(这个错了,都要捕获异常),sleep需要捕获异常(可能发生超时等待)
import java.util.concurrent.TimeUnit;

        try {
            //更好的睡眠
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Integer i=new Integer(1);
        try {
            i.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

4. 卖票的代码

/**
 * 真正的多线程开发,公司中的开发,降低耦合性
 * 线程就是一个单独的资源类,没有任何附属的操作!
 * 1、 属性、方法
 */
public class SaleTicketDemo01 {
    public static void main(String[] args) {
        // 并发:多线程操作同一个资源类, 把资源类丢入线程
        Ticket ticket = new Ticket();

        // @FunctionalInterface 函数式接口,jdk1.8  lambda表达式 (参数)->{ 代码 }
        new Thread(()->{
            for (int i = 1; i < 40 ; i++) {
                ticket.sale();
            }
        },"A").start();
    }
}

// 资源类 OOP
class Ticket {
    // 属性、方法
    private int number = 30;

    // 卖票的方式
    // synchronized 本质: 队列,锁
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余:"+number);
        }
    }

}

5. Lock锁

  • java.util.concurrent.locks

    • Condition
    • Lock
    • ReadWriteLock 读写锁
  • 所有已知实现类:

    • ReentrantLock

    • ReentrantReadWriteLock.ReadLock

    • ReentrantReadWriteLock.WriteLock

entrant
英
/ˈentrənt/
美
/ˈentrənt/
全球发音
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n.
进入者;新会员;参加竞赛者;新工作者

ReentrantLock

  • 源码
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

fail
v.
失败;未能做到,未能做;辜负,使失望;不及格,未能通过;出故障,失灵;衰弱,衰退;破产,倒闭;歉收;不下雨,下雨少;忘记
n.
不及格;<非正式>过失,失败

fair
adj.
公平的;合理的,公正的;相当好的;(数量、大小)相当大的;浅色的,(肤色)白皙的,(头发)金色的;晴朗的;顺风的;普通的;美丽的;界内的;<旧>(手段,方法)温和的,非暴力的;<旧>(言语,谈话,许诺)花言巧语的

adv.
公平地,公正地;非常;正面地,直接地;清楚地

公平锁:十分公平:可以先来后到

非公平锁:十分不公平:可以插队 (默认)

使用

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

}
        // 并发:多线程操作同一个资源类, 把资源类丢入线程
        Ticket2 ticket = new Ticket2();

        new Thread(()->{for (int i = 1; i < 40 ; i++) ticket.sale();},"A").start();

Synchronized 和 Lock

Synchronized 和 Lock 区别

1、Synchronized 内置的Java关键字, Lock 是一个Java接口

2、Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁

3、Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁

4、Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待

去;

        lock.tryLock()

5、Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以

自己设置);

6、Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码

6. 生产者 消费者

  • Synchronized ,wait,notify

传统写法

/**
 * 线程之间的通信问题:生产者和消费者问题!  等待唤醒,通知唤醒
 * 线程交替执行  A   B 操作同一个变量   num = 0
 * A num+1
 * B num-1
 */
public class A {
    public static void main(String[] args) {
        Data data = new Data();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"A").start();
		
        //然后再写 B线程
    }
}


// 判断等待,业务,通知
class Data{ // 数字 资源类

    private int number = 0;

    //+1
    public synchronized void increment() throws InterruptedException {
        while (number!=0){  //0
            // 等待
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        // 通知其他线程,我+1完毕了
        this.notifyAll();
    }

    //-1
    public synchronized void decrement() throws InterruptedException {
        while (number==0){ // 1
            // 等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        // 通知其他线程,我-1完毕了
        this.notifyAll();
    }

}

问题存在,A B C D 4 个线程!

  • 把上面的 while改为if,产生虚假唤醒

虚假唤醒

线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒 。 虽然这在实践中很少会发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。 换句话说,等待应该总是出现在循环中,就像这样:

  synchronized (obj) {
         while (<condition does not hold>)
             obj.wait(timeout);
         ... // Perform action appropriate to condition
     } 
        while (number!=0){  //0
            // 等待
            this.wait();
        }

7. Condition

  • Condition因素出Object监视器方法( waitnotifynotifyAll )成不同的对象,以得到具有多个等待集的每个对象,通过将它们与使用任意的组合的效果Lock实现。 Lock替换synchronized方法和语句的使用, Condition取代了对象监视器方法的使用。

直接唤醒全部

// 判断等待,业务,通知
class Data2{ // 数字 资源类

    private int number = 0;

    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    //condition.await(); // 等待
    //condition.signalAll(); // 唤醒全部
    //+1
    public void increment() throws InterruptedException {
        lock.lock();
        try {
            // 业务代码
            while (number!=0){  //0
                // 等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            // 通知其他线程,我+1完毕了
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    //-1
    public void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number==0){ // 1
                // 等待
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName()+"=>"+number);
            // 通知其他线程,我-1完毕了
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

精准的通知和唤醒线程

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; // 1A  2B  3C

    public void printA(){
        lock.lock();
        try {
            // 业务,判断-> 执行-> 通知
            while (number!=1){
                // 等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
            
            // 唤醒,唤醒指定的人,B
            number = 2;
            condition2.signal();
            
        } 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()+"=>BBBBBBBBB");
            
            // 唤醒,唤醒指定的人,c
            number = 3;
            condition3.signal();
        } 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()+"=>CCCCCCC");
            
            // 唤醒,唤醒指定的人,c
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值