JUC一

警醒自己不断学习和成长

正式学习的准备工作

JUC并发编程

1.什么是JUC

JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包,JDK 1.5开始出现的。

2.进程和线程回顾

什么是进程和线程?

进程:是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用,例如:QQ.exe

线程:是拥有资源和独立运行的最小单位,也是程序执行的最小单位.

一个进程可以包含多个线程,一个进程至少有一个线程!Java程序至少有两个线程:GC,main

并发、并行

并发:多个线程操作同一个资源,交替执行的过程!

并行:多个线程同时执行!只有在多核CPU下才能完成!

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

线程有几种状态

线程有6种状态

public enum State {    // java能够创建线程吗? 不能!    // 新建    NEW,    // 运行    RUNNABLE,    // 阻塞    BLOCKED,    // 等待    WAITING,    // 延时等待    TIMED_WAITING,    // 终止!    TERMINATED;}

Java不能够创建线程!!!(线程是操作系统的资源)

线程的状态切换

wait/sleep的区别

1、类不同!

wait——Object类   sleep——Thread类在juc编程中,线程休眠怎么实现?        //时间单位TimeUnit.SECONDS.sleep(3);?

2、会不会释放资源

sleep:抱着锁睡得,不会释放锁;wait会释放锁。

3、使用的范围是不同的

wait和notify是一组,一般在线程通信的时候使用;

sleep就是一个单独的方法,在哪里都可以调用。

4、关于异常

sleep需要捕获异常

3.Lock锁

synchronized 传统的方式

代码:

package com.rudd.demo;?import java.util.concurrent.TimeUnit;?/** * 传统的synchronized * 企业级开发: * 1.架构:高内聚,低耦合 * 2.套路:线程操作资源类,资源类是单独的。 */public class Test1 {?    public static void main(String[] args) {        //1.新建资源类        Ticket ticket = new Ticket();        //2.线程操纵资源类        new Thread(()->{            for (int i = 1; i < 41; i++) {                ticket.saleTicket();            }        },"A").start();        new Thread(()->{            for (int i = 1; i < 41; i++) {                ticket.saleTicket();            }        },"B").start();        new Thread(()->{            for (int i = 1; i < 41; i++) {                ticket.saleTicket();            }        },"C").start();    }}//单独的资源类应该只有:属性和方法class Ticket{?    private int number = 30;?    //synchronized 关键字    public synchronized void saleTicket(){        if(number>0){            System.out.println(Thread.currentThread().getName()+"卖出第"+(number--)+"票,还剩:"+number);        }    }}

Lock锁

代码:

package com.rudd.demo;?import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;?public class Test02 {?    public static void main(String[] args) {        //1.新建资源类        Ticket2 ticket = new Ticket2();        //2.线程操纵资源类,所有的函数式接口都可以用lambda表达式简化        //lambda表达式:(参数)->{具体的代码}        new Thread(()->{            for (int i = 1; i < 41; i++) {                ticket.saleTicket();            }        },"A").start();        new Thread(()->{            for (int i = 1; i < 41; i++) {                ticket.saleTicket();            }        },"B").start();        new Thread(()->{            for (int i = 1; i < 41; i++) {                ticket.saleTicket();            }        },"C").start();    }}?class Ticket2{    /*     * 使用Lock,它是一个对象     * ReentrantLock 可重入锁     * ReentrantLock  默认是非公平锁     * 非公平锁:不公平(插队,后面的线程可以插队)     * 公平锁:公平(只能排队,后面的线程无法插队)     */    private Lock lock = new ReentrantLock();    private int number = 30;?    public void saleTicket(){        //加锁        lock.lock();        try {            if(number>0){                System.out.println(Thread.currentThread().getName()+"卖出第"+(number--)+"票,还剩:"+number);            }        }catch (Exception e){            e.printStackTrace();        }finally {            //解锁            lock.unlock();        }    }}

synchronized和Lock的区别

  1. synchronized是一个关键字;Lock是一个对象
  2. synchronized无法尝试获取锁,Lock可以尝试获取锁,会进行判断;
  3. synchronized会自动释放锁(a线程执行完毕,b如果异常了,也会释放锁),Lock锁是手动释放锁,如果不释放就会死锁
  4. synchronizedsynchronizedsynchronized(线程A(获得锁,如果阻塞),线程B(等待,一直等待));Lock可以尝试获取锁,失败了之后就放弃。

  5. synchronized一定是非公平的锁,但是Lock锁可以是公平的,通过参数设置;
  6. 代码量特别大的时候,我们一般使用Lock实现精准控制,synchronized适合代码量较小的同步问题。

4.生产者和消费者

线程和线程之间本来是不能通信的,但是有时候我们需要线程之间可以协调操作:等待唤醒机制

synchronized

package com.rudd.demo;/*    synchronized?    目的:有两个线程:A B,还有一个初始值为0的变量    实现两个线程交替执行,对该变量进行+1和-1操作,交替10次。?    传统的wait和notify方法不能实现精准唤醒。 */public class Test03 {    public static void main(String[] args){        Data data = new Data();        //负责+1操作        new Thread(()->{            for (int i = 0; i < 10; i++) {                try {                    data.increment();                }catch (Exception e){                    e.printStackTrace();                }            }        },"A").start();        //负责-1操作        new Thread(()->{            for (int i = 0; i < 10; i++) {                try {                    data.decrement();                }catch (Exception e){                    e.printStackTrace();                }            }        },"B").start();        new Thread(()->{            for (int i = 0; i < 10; i++) {                try {                    data.increment();                }catch (Exception e){                    e.printStackTrace();                }            }        },"C").start();        new Thread(()->{            for (int i = 0; i < 10; i++) {                try {                    data.decrement();                }catch (Exception e){                    e.printStackTrace();                }            }        },"D").start();    }}?//资源类//线程之间的通信:判断    执行  通知class Data{    private int number = 0;?    public synchronized void increment() throws Exception{        //不要用if,会导致需要唤醒        while(number!=0){//1.判断是否需要等待            this.wait();        }        number++;//2.执行        System.out.println(Thread.currentThread().getName()+":::"+number);        this.notifyAll();//3.通知:唤醒所有线程    }?    public synchronized void decrement() throws Exception{        //不要用if,会导致需要唤醒        while(number!=1){//1.判断是否需要等待            this.wait();        }        number--;//2.执行        System.out.println(Thread.currentThread().getName()+":::"+number);        this.notifyAll();//3.通知:唤醒所有线程    }}

用if判断可能会导致虚假唤醒

Lock和Condition实现精准唤醒

传统的监视器:Object,JUC的监视器:Condition

package com.rudd.demo;?import sun.awt.windows.ThemeReader;?import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;?/*    实现线程交替执行:        主要的实现目标:精准的唤醒线程!        三个线程:A,B,C        三个方法:A p5,B p10,C p15一次循环。? */public class Test04 {    public static void main(String[] args) {        Data2 data = new Data2();        new Thread(() -> {            for (int i = 0; i < 10; i++) {                data.print5();            }        }, "A").start();        new Thread(() -> {            for (int i = 0; i < 10; i++) {                data.print10();            }        }, "B").start();        new Thread(() -> {            for (int i = 0; i < 10; i++) {                data.print15();            }        }, "C").start();    }}??class Data2 {    Lock lock = new ReentrantLock();    Condition condition1 = lock.newCondition();    Condition condition2 = lock.newCondition();    Condition condition3 = lock.newCondition();    private int number = 1;//1-A线程;2—B线程;3—C线程?    public void print5() {        lock.lock();        try {            //1.判断            while (number != 1) {                condition1.await();//等待            }            //2.执行            for (int i = 0; i < 5; i++) {                System.out.println(Thread.currentThread().getName() + "\t" + i);            }            //3.通知第二个线程干活            number = 2;            condition2.signal();//唤醒        } catch (Exception e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }?    public void print10() {        lock.lock();        try {            //1.判断            while (number != 2) {                condition2.await();            }            //2.执行            for (int i = 0; i < 10; i++) {                System.out.println(Thread.currentThread().getName() + "\t" + i);            }            //3.通知第三个线程干活            number = 3;            condition3.signal();        } catch (Exception e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }?    public void print15() {        lock.lock();        try {            //1.判断            while (number != 3) {                condition3.await();            }            //2.执行            for (int i = 0; i < 15; i++) {                System.out.println(Thread.currentThread().getName() + "\t" + i);            }            //3.通知第一个线程干活            number = 1;            condition1.signal();        } catch (Exception e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }}

5.八锁现象,搞懂锁

synchronized实现同步的基础:

1、普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁

2、静态同步方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁

3、同步代码块,锁是括号里面的对象,对给定对象加锁,进入同步代码块前要获得给定对象的锁。

6.集合类不安全

List

安全的List解决方案:

List<String> list1 = new Vector<String>();List<String> list2 = Collections.synchronizedList(new ArrayList<String>());/* CopyOnWrite:写入时复制(COW思想)   CopyOnWriteArrayList,是一个写入时复制的容器,它是如何工作的呢?简单来说,就是平时查询的时候,都不需要加锁,随便访问,只有在写入/删除的时候,才会从原来的数据复制一个副本出来,然后修改这个副本,最后把原数据替换成当前的副本。修改操作的同时,读操作不会被阻塞,而是继续读取旧的数据。*/List<String> list3 = new CopyOnWriteArrayList<String>();//class CopyOnWriteArrayList;public boolean add(E e) {    final ReentrantLock lock = this.lock;    lock.lock();    try {        Object[] elements = getArray();        int len = elements.length;        Object[] newElements = Arrays.copyOf(elements, len + 1);        newElements[len] = e;        setArray(newElements);        return true;    } finally {        lock.unlock();    }}?

Set

安全的Set解决方案:

Set<String> set1 = Collections.synchronizedSet(new HashSet<String>());Set<String> set2 = new CopyOnWriteArraySet<String>();

HashSet的底层就是:HashMap

Map

安全的Map解决方案:

Map<String,String> map1 = new Hashtable<String,String>();        Map<String,String> map2 = Collections.synchronizedMap(new HashMap<String,String>());        Map<String,String> map3 = new ConcurrentHashMap<String,String>();

HashMap的底层数据结构:链表+红黑树

原文地址:https://www.cnblogs.com/tianxc/p/12398206.html

时间: 2024-10-16 09:37:29

JUC一的相关文章

Java多线程系列--“JUC锁”11之 Semaphore信号量的原理和示例

概要 本章,我们对JUC包中的信号量Semaphore进行学习.内容包括:Semaphore简介Semaphore数据结构Semaphore源码分析(基于JDK1.7.0_40)Semaphore示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3534050.html Semaphore简介 Semaphore是一个计数信号量,它的本质是一个"共享锁". 信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可

Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例

概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)CyclicBarrier示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3533995.html CyclicBarrier简介 CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点 (common barrier p

Java JUC之Atomic系列12大类实例讲解和原理分解

Java JUC之Atomic系列12大类实例讲解和原理分解 2013-02-21      0个评论       作者:xieyuooo 收藏    我要投稿 在java6以后我们不但接触到了Lock相关的锁,也接触到了很多更加乐观的原子修改操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,以及并发中的ABA问题,本文讲述Atomic系列的类的实现以及使用方法,其中包含: 基本类:AtomicInteger.AtomicLong.Atomic

使用JUC并发工具包的Lock和Condition,实现生产者和消费者问题中的有界缓存

JDK5.0之前,用java实现生产者和消费者的唯一方式就是使用synchronized内置锁和wait/notify条件通知机制.JDK5.0之后提供了显示锁Lock和条件队列Condition,与内置锁和内置条件队列相对应,但是显示的锁和条件队列,功能更强大,更灵活.此外JDK5.0之后还提供了大量很有用的并发工具类,如BlockingQueue等,基于这些数据结构,能够方便.快速.高效的构建自己应用需要的效果.这里我们简单使用下显示锁和条件队列,来模拟有界缓存的实现,功能类似于JDK内置的

Java - &quot;JUC线程池&quot; Callable与Future

Java多线程系列--"JUC线程池"06之 Callable和Future Callable 和 Future 简介 Callable 和 Future 是比较有趣的一对组合.当我们需要获取线程的执行结果时,就需要用到它们.Callable用于产生结果,Future用于获取结果. 1. Callable Callable 是一个接口,它只包含一个call()方法.Callable是一个返回结果并且可能抛出异常的任务. 为了便于理解,我们可以将Callable比作一个Runnable接

Java多线程系列--“JUC锁”05之 非公平锁

获取非公平锁(基于JDK1.7.0_40) 非公平锁和公平锁在获取锁的方法上,流程是一样的:它们的区别主要表现在"尝试获取锁的机制不同".简单点说,"公平锁"在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待):而"非公平锁"在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁).在前面的"Java多线程系列--"JUC锁"03之 公平锁(一)&q

java多线程系类:JUC集合:01之框架

概要 之前,在"Java 集合系列目录(Category)"中,讲解了Java集合包中的各个类.接下来,将展开对JUC包中的集合进行学习.在学习之前,先温习一下"Java集合包".本章内容包括:Java集合包JUC中的集合类 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3498454.html Java集合包 在"Java 集合系列01之 总体框架"中,介绍java集合的架构.主体内容包括Colle

java多线程系类:JUC原子类:03之AtomicLongArray原子类

概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数组类型的原子类进行介绍.内容包括:AtomicLongArray介绍和函数列表AtomicLongArray源码分析(基于JDK1.7.0_40)AtomicLongArray示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514604.html

十一、JUC包中的锁

JUC,即java.util.concurrent. 悲观锁和乐观锁 悲观锁和乐观锁是一种思想. 悲观锁,持有一种悲观的态度,认为会出现很坏的情况,所以,先做预防措施.独占锁是一种悲观锁,synchronized就是一种独占锁. 而乐观锁,则是持有一种持有种乐观的态度,认为不会出现什么问题,有问题了再说. 对于常用多线程编程的人估计知道,在jdk5之前,在多线程编程的时候,为了保证多个线程对一个对象同时进行访问时,我们需要加同步锁synchronized,保证对象的在使用时的正确性,但是加锁的机

【目录】JUC锁框架目录

JUC锁框架的目录整理如下: 1. [JUC]JUC锁框架综述 2. [JUC]JDK1.8源码分析之LockSupport(一) 3. [JUC]JDK1.8源码分析之AbstractQueuedSynchronizer(二) 4. [JUC]JDK1.8源码分析之ReentrantLock(三) 5. [JUC]JDK1.8源码分析之CyclicBarrier(四) 6. [JUC]JDK1.8源码分析之CountDownLatch(五) 7. [JUC]JDK1.8源码分析之Semapho