JUC并发编程思想

一、Java原生的并发包、常用的工具类

  • java.util.concurrent 并发工具包
  • java.util.concurrent.atomic 原子包
  • java.util.concurrent.locks 锁
  • java.util.function 函数

二、什么是线程和进程?
进程: wexi.exe
线程: 打字、自动保存。。。
一个进程可以包含多个线程,一个进程至少有两个线程!java程序至少两个线程:GC、 Main
并发、并行
并发:多个线程操作同一个资源、交替执行的过程!
并行:多个线程同时执行!只有在多核CPU下才能完成!
所有我们使用多个线程或者并发编程目的:提高效率,让CPU一直工作,达到最高处理性能!

三、线程有几种状态
线程有六状态,学会面向源码学习
public enum State {
//java能够创建线程?
NEW
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//延时等待
TIMED_WAITING,
//终止
TERMINATED;
}

四、Wait/Sleep区别

1、类不同!

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

2、会不会释放资源
Sleep:抱着锁睡着、不会释放锁!wait会释放锁

3、使用的范围是不同
Wait和notify是一组,一般在线程通信的时候使用!
Sleep 就是一个单独的方法、在哪里都可以用!

4、关于异常
Sleep需要捕获异常!

五、Lock锁
Synchronized 传统的使用
package com.coding.demo01;
import java.util.concurrent.TimeUnit;
//传统的 Synchronized
//Synchronized 方法 和 Synchronized 类

/**

  • 1、架构思想: 高内聚 、底耦合
  • 2、并发编程思想:线程操作资源类、资源类是单独类
    */
public class Demo01 {
    public static void main(String[] args) {
//        new Thread(new Ticket()).start();
        //1、新建资源类
        final Ticket1 ticket = new Ticket1();
        //2、线程操作资源类
        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 40; i++) {
                    ticket.saleTicket();

                }
            }
        },"A").start();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 40; i++) {
                    ticket.saleTicket();

                }
            }
        },"B").start();

        new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 40; i++) {
                    ticket.saleTicket();

                }
            }
        },"C").start();
    }

}

//class Ticket implements Runnable {
//
//    public void run() {
//
//    }
//}
//单独的资源类,属性和方法
class Ticket1  {
    private  int number =30;
    //同步锁,测试=》close
    //synchronized  是一个关键字
    public synchronized void saleTicket(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+"卖出第"+(number--)+"票,还剩:"+number);
        }}}

Lock锁

package com.coding.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK:
 * -- User: tanwei
 * -- Date: 2020/6/18
 * -- Time: 10:32 上午
 * --
 * JUC 之后操作
 * lock锁 +lambda 表达式
 */
public class Dome02 {
    public static void main(String[] args) {
        //1.新建资源类
        Ticket02 ticket02 = new Ticket02();

        //2.线程操作资源类,所有的函数接口都可以用lambda表示简化!
        //()->{}lambda表达式(参数) ->{具体代码}
        new Thread(()->{ for (int i = 0; i <40; i++) {ticket02.saleTicket(); } },"A").start();
        new Thread(()->{ for (int i = 0; i <40; i++) {ticket02.saleTicket(); } },"B").start();
        new Thread(()->{ for (int i = 0; i <40; i++) {ticket02.saleTicket(); } },"C").start();
    }
}

//依旧是一个资源类
class Ticket02 {
    //使用lock,它是一个对象

    //ReentrantLock 可重入锁: 回家:大门(卧室,厨房。。。)
    //ReentrantLock    默认是非公平锁!
    //非公平是: 不公平 (插队,后面线程可以插队)
    //公平是: 公平 (只能排到,后面线程不可以插队)
    private Lock lock = new ReentrantLock();
    private int number = 30;

    public synchronized 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、Synchronized(线程A(获得锁,如果阻塞),线程B(等待);)lock 可以尝试获取锁、失败了之后就放弃

在这里插入图片描述5、Synchronized 一定是非公平的,但是Lock 锁可以试公平的、可以通过参数设置;
6、代码量特别大的时候,我们一棒使用lock实现精准控制、Synchronized 适合代码量比较小的同步问题;

七、生产者消费者问题
单例模式 排序算法 死锁、生成者消费者
线程和线程之间本来不能通信的、但是有时候我们需要线程之间协调操作:
Synchronized:普通版

package com.coding.demo01;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK:
 * -- User: tanwei
 * -- Date: 2020/6/18
 * -- Time: 10:34 上午
 * --
 *
 *
 * Synchronized 版
 * 目的: 有两个线程:A B,还有一个值初始为0,
 *       实现两个线程交替执行,对该变量 +1,-1;交替10次
 */
public class Demo03 {

    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()+"\t"+number);
        //通知
        this.notifyAll();//唤醒所有线程
    }
    //-1
    public  synchronized  void decrement() throws InterruptedException {
        if(number==0){//判断是否需要等待
            this.wait();
        }
        number--;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //通知
        this.notifyAll();//唤醒所有线程
    }}

传统的唤醒

package com.coding.demo01;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK:
 * -- User: tanwei
 * -- Date: 2020/6/18
 * -- Time: 10:34 上午
 * --
 * Synchronized 版
 * 目的: 有两个线程:A B,还有一个值初始为0,
 *       实现两个线程交替执行,对该变量 +1,-1;交替10次
 *
 * 传统的wait 和notifyAll 不能精准唤醒
 */
public class Demo04 {

    public static void main(String[] args) {
        Data4 data = new Data4();
        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.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } 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 Data4 {
    private int number = 0;

    //+1
    public synchronized  void  increment() throws InterruptedException {
        while (number!=0){//判断是否需要等待
            this.wait();
        }
        number++;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //通知
        this.notifyAll();//唤醒所有线程
    }
    //-1
    public  synchronized  void decrement() throws InterruptedException {
        while (number==0){//判断是否需要等待
            this.wait();
        }
        number--;//执行
        System.out.println(Thread.currentThread().getName()+"\t"+number);
        //通知
        this.notifyAll();//唤醒所有线程
    }}
package com.coding.demo01;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK:
 * -- User: tanwei
 * -- Date: 2020/6/18
 * -- Time: 1:11 下午
 * --
 * 实现线程交换执行
 * 主要的实现目标,;精准的唤醒线程!
 * <p>
 * 三个线程:A B C
 * 三个方法:A p5 B p10 C p15 依次循环
 */
public class Demo05 {
    public static void main(String[] args) {
        Data3 data = new Data3();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.print5();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.print10();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.print15();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
    }
}

class Data3 {
    private int number = 1;//1A 2B 3C
    private Lock lock = new ReentrantLock();
    //实现精准访问
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();

    public void print5() throws InterruptedException {
        lock.lock();
        //判断
        try {
            while (number != 1) {
                condition1.await();
            }
            //执行
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            //通知第二个线程干活
            number = 2;
            condition2.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void print10() throws InterruptedException {
        lock.lock();
        //判断
        try {
            while (number != 2) {
                condition2.await();
            }
            //执行
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            //通知
            number = 3;
            condition3.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }


    public void print15() throws InterruptedException {
        lock.lock();
        //判断
        try {
            while (number != 3) {
                condition3.await();
            }
            //执行
            for (int i = 0; i < 15; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
            //通知
            number = 1;
            condition1.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

新的技术、一定是可以替换一些旧技术!

八、八锁现象线程彻底解锁

package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * 标准的访问情况下,先执行 sendEmail  还是 sendSMS
 *
 * 被 synchronized 修饰的方式,锁的对象是方法的调用者,所有说这两个方法调用的对象是同一个先调用先执行
 */
public class Lock01 {

    public static void main(String[] args) throws InterruptedException {

        Phone phone = new Phone();
        new Thread(() -> {
            phone.sendEmail();
        },"A").start();

        TimeUnit.SECONDS.sleep(2);

        new Thread(() -> {
            phone.sendSMS();
        },"B").start();
    }
}


class Phone {
    public synchronized void sendEmail() {
        System.out.println("sendEmail");
    }


    public synchronized void sendSMS() {
        System.out.println("sendSMS");
    }
}

package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 *
 * sendEmail暂停三秒,先执行 sendEmail  还是 sendSMS
 *
 * 被 synchronized 修饰的方式,锁的对象是方法的调用者,所有说这两个方法调用的对象是同一个先调用先执行
 */
public class Lock02 {

    public static void main(String[] args) throws InterruptedException {

        Phone02 phone = new Phone02();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();

        TimeUnit.SECONDS.sleep(2);

        new Thread(() -> {
            phone.sendSMS();
        },"B").start();
    }
}


class Phone02 {
    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public synchronized void sendSMS() {
        System.out.println("sendSMS");
    }
}
package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * <p>
 * 增加一个普通方法,先执行 sendEmail  还是 sendSMS
 * <p>
 *
 *   新增加的这个方法没有synchronized 修饰 不是同步方法、不受影响
 */
public class Lock03 {

    public static void main(String[] args) throws InterruptedException {

        Phone03 phone = new Phone03();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            phone.sendSMS();
        }, "B").start();
    }
}


class Phone03 {
    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public void sendSMS() {
        System.out.println("sendSMS");
    }
}
package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * <p>
 * 两个手机 请问先执行sendemail  还是 sendSMS
 * <p>
 *
 *  被synchronized  修饰的方式 ,锁的对象是方法的调用者,所以说这里两个方法调用的对象是同一个对象先调用先执行
 */
public class Lock04 {

    public static void main(String[] args) throws InterruptedException {

        Phone04 phone = new Phone04();
        Phone04 phone1 = new Phone04();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            phone1.sendSMS();
        }, "B").start();
    }
}


class Phone04 {
    public synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public synchronized void sendSMS() {

        System.out.println("sendSMS");
    }
}


package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * <p>
 *     Lock05.class 模板,只有一个static
 *     new Lock05(), 可以创建多个对象
 * 两个静态方法 请问先执行sendemail  还是 sendSMS
 * <p>
 *
 *  只要方法被static 修饰 、锁的对象就是class模板对象,这个则是全局唯一!所以说这里是同一个对象
 */
public class Lock05 {

    public static void main(String[] args) throws InterruptedException {

        Phone05 phone = new Phone05();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            phone.sendSMS();
        }, "B").start();
    }
}


class Phone05 {
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public static synchronized void sendSMS() {

        System.out.println("sendSMS");
    }
}


package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * <p>
 *     Lock05.class 模板,只有一个static
 *     new Lock05(), 可以创建多个对象
 * 两个静态方法 请问先执行sendemail  还是 sendSMS
 * <p>
 *
 *  只要方法被static 修饰 、锁的对象就是class模板对象,这个则是全局唯一!所以说这里是同一个对象
 */
public class Lock06 {

    public static void main(String[] args) throws InterruptedException {

        Phone06 phone = new Phone06();
        Phone06 phone1 = new Phone06();

        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            phone1.sendSMS();
        }, "B").start();
    }
}


class Phone06 {
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public static synchronized void sendSMS() {

        System.out.println("sendSMS");
    }
}


package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * <p>
 *     Lock05.class 模板,只有一个static
 *     new Lock05(), 可以创建多个对象
 *
 * <p>
 *
 *     synchronized 锁的是这个调用对象
 *     static 锁的是这个类的class 模板
 *
 *     这里是两个锁
 *
 */
public class Lock07 {

    public static void main(String[] args) throws InterruptedException {
        Phone07 phone = new Phone07();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            phone.sendSMS();
        }, "B").start();
    }
}


class Phone07 {
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public  synchronized void sendSMS() {

        System.out.println("sendSMS");
    }
}


package com.coding.lock8;

import java.util.concurrent.TimeUnit;

/**
 * -- Created by IntelliJ IDEA.
 * -- REMARK: lock
 * -- User: tanwei
 * -- Date: 2020/6/19
 * -- Time: 2:34 下午
 * --
 * <p>
 * Lock05.class 模板,只有一个static
 * new Lock05(), 可以创建多个对象
 *
 * <p>
 * <p>
 * synchronized 锁的是这个调用对象
 * static 锁的是这个类的class 模板
 * <p>
 * 这里是两个锁
 */
public class Lock08 {

    public static void main(String[] args) throws InterruptedException {
        Phone08 phone = new Phone08();
        Phone08 phone1 = new Phone08();
        new Thread(() -> {
            try {
                phone.sendEmail();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

        TimeUnit.SECONDS.sleep(1);

        new Thread(() -> {
            phone1.sendSMS();
        }, "B").start();
    }
}


class Phone08 {
    public static synchronized void sendEmail() throws InterruptedException {
        TimeUnit.SECONDS.sleep(3);
        System.out.println("sendEmail");
    }


    public synchronized void sendSMS() {

        System.out.println("sendSMS");
    }
}

总结:
1 、new this 调用的这个对象,是一个具体的对象
2、static class 唯一的一个模板!
在编写多线程的时候,只需要搞明白这个到底锁的是什么就不出错了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值