JUC并发编程入门学习笔记(狂神说)

目录

1. 什么是JUC

2. 线程和进程

1)进程

2)线程

3)并发

4)并行

5)线程的状态

6)wait/sleep

3.Lock

1)传统的 synchronized

2)Lock

3).Synchronized 与Lock 的区别

4. 生产者和消费者的关系

1)Synchronzied 版本

2)JUC版本的生产者和消费者问题

5、6锁现象

6、不安全的集合类

HashSet底层是什么?

7、Callable

 8、常用的辅助类(必会!)

8.1 CountDownLatch​

8.2 CyclickBarrier

8.3 Semaphore

9、读写锁

 10、阻塞队列

BlockingQueue

如何使用阻塞队列呢?

SynchronousQueue同步队列

11、线程池(重点)

12、四大函数式接口(必需掌握)

13、Stream流式计算

14、ForkJoin

15、异步回调

(1)没有返回值的runAsync异步回调

 (2)有返回值的异步回调supplyAsync

16.深入理解CAS

17、原子引用

18. 各种锁的理解

1、公平锁、非公平锁

2、可重入锁

3.自旋锁

4.死锁


因为热爱所以坚持,因为热爱所以等待。熬过漫长无戏可演的日子,终于换来了人生的春天,共勉!!!

1. 什么是JUC

JUC就是java.util.concurrent下面的类包,专门用于多线程的开发。

2. 线程和进程

进程是操作系统中的应用程序、是资源分配的基本单位,线程是用来执行具体的任务和功能,是CPU调度和分派的最小单位

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

1)进程

一个程序,QQ.EXE Music.EXE;数据+代码+pcb

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

Java默认有几个线程?2个线程! main线程、GC线程

2)线程

开了一个进程Typora,写字,等待几分钟会进行自动保存(线程负责的)

对于Java而言:Thread、Runable、Callable进行开启线程的。

提问?JAVA真的可以开启线程吗? 开不了的!

Java是没有权限去开启线程、操作硬件的,这是一个native的一个本地方法,它调用的底层的C++代码。

  public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
	//这是一个C++底层,Java是没有权限操作底层硬件的
    private native void start0();

3)并发

多线程操作同一个资源

  • CPU 只有一核,模拟出来多条线程,天下武功,唯快不破。那么我们就可以使用CPU快速交替,来模拟多线程。
  • 并发编程的本质:充分利用CPU的资源!

4)并行

  • CPU多核,多个线程可以同时执行。 我们可以使用线程池!

获取cpu的核数

public class Test1 {
    public static void main(String[] args) {
        //获取cpu的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

5)线程的状态

Thread类中有个内部枚举,可以看到六种状态

public enum State {
        /**
         * Thread state for a thread which has not yet started.
         */
    	//运行
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
    	//运行
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
    	//阻塞
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
    	//等待
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
    	//超时等待
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
    	//终止
        TERMINATED;
    }

6)wait/sleep

1、来自不同的类

wait => Object

sleep => Thread

一般情况企业中使用休眠是:

TimeUnit.DAYS.sleep(1); //休眠1天
TimeUnit.SECONDS.sleep(1); //休眠1s

2、关于锁的释放

wait 会释放锁;

sleep睡觉了,不会释放锁

3、使用的范围是不同的

wait 必须在同步代码块中;

sleep 可以在任何地方睡;

4、是否需要捕获异常

wait必须要捕获异常;

sleep必须要捕获异常;

3.Lock

1)传统的 synchronized

2)Lock

image-20200810221525974

 image-20200810221731649

公平锁: 十分公平,必须先来后到~;

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

3).Synchronized 与Lock 的区别

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

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

3、Synchronized 会自动释放锁,lock必须要手动加锁和手动释放锁!可能会遇到死锁

4、Synchronized 线程1(获得锁->阻塞)、线程2(等待);lock就不一定会一直等待下去,lock会有一个trylock去尝试获取锁,不会造成长久的等待。

5、Synchronized 是可重入锁,不可以中断的,非公平的;Lock,可重入的,可以判断锁,可以自己设置公平锁和非公平锁

4. 生产者和消费者的关系



1)Synchronzied 版本

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();
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"B").start();
    }
}
class Data{
    //数字  资源类
    private int number = 0;

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

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

}

结果:实现A,B之间的生产者消费者问题

 但是存在一个问题,现在是A,B连两个线程,现在如果我有四个线程A B C D

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();
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"B").start();
        
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"C").start();
        
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"D").start();
    }
}
class Data{
    //数字  资源类
    private int number = 0;

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

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

}

结果:出现错误

解决方案: if 改为while即可,防止虚假唤醒

这样就不存在问题了:

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();
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"B").start();
        
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"C").start();
        
        new Thread(()->{for(int i=0;i<10;i++) {
            try {
                data.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }},"D").start();
    }
}
class Data{
    //数字  资源类
    private int number = 0;

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

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

}

结果:成功实现四个线程互斥

2)JUC版本的生产者和消费者问题

await、signal 替换 wait、notify

在这里插入图片描述

 在这里插入图片描述

public class B {
	public static void main(String[] args) {
		Data2 data2 = new Data2();
		
		new Thread(() ->  {for (int i = 0; i < 10; i++) {
			data2.increment();
		}},"A").start();
		
		new Thread(() ->  {for (int i = 0; i < 10; i++) {
			data2.decrement();
		}},"B").start();
		
		new Thread(() ->  {for (int i = 0; i < 10; i++) {
			data2.increment();
		}},"C").start();
		
		new Thread(() ->  {for (int i = 0; i < 10; i++) {
			data2.increment();
		}},"D").start();
		
	}
}
class Data2 {
	private int number = 0;
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();
	
	public void increment() {
		lock.lock();	
		try {
			while (number != 0) {
				//等待
				condition.await();
			}
		    number++;
		    System.out.println(Thread.currentThread().getName()+"=>"+number);
		    //通知其他线程,+1完毕了
		    condition.signalAll();
		} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
	}
	
	public void decrement() {
		lock.lock();	
		try {
			while (number == 0) {
				//等待
				condition.await();
			}
		    number--;
		    System.out.println(Thread.currentThread().getName()+"=>"+number);
		    //通知其他线程,+1完毕了
		    condition.signalAll();
		} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
		}
	}
}

结果:实现互斥操作

 相比于wait和notify方法只能随机唤醒线程,Condition的优势:精准的通知和唤醒的线程!

通过condition1、condition2 、condition3 的交替使用,完成流程控制A-->B-->C

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Free的午后

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值