Juc(上)

1、什么是JUC?

java.util 工具包、包、分类

业务:普通的线程代码 Thread

Runnable 没有返回值、效率相比于Callable相对较低,所以开发中大多使用Callable

 

 

 并发(多线程操作同一个资源)

  •   cpu单核,模拟出来多条线程,天下武功,唯快不破,快速交替

并行(多个人一起行走)

  •   cpu多核,多个线程可以同时执行; 要提高性能可以用线程池
public class Test1 {
    public static void main(String[] args) {
        // 获取cpu的核数
        System.out.println(Runtime.getRuntime().availableProcessors());
    }
}

并发编程的本质:充分利用cpu的资源

 

线程的状态:(源码中)

 

 

 

wait和sleep的区别

1、来自不同的类

  • wait => Object
  • sleep => Thread

2、是否释放锁

  • wait不释放锁
  • sleep释放锁

3、使用的范围不同

  • wait必须在同步代码块中
  • sleep可以在任何地方睡

4、是否需要捕获异常

  • wait不需要捕获异常
  • sleep必须捕获异常(因为可能会发生超时等待的状况)

 

三、Lock锁(重点)

 

 

 

 

 

 

 

 ReentrantLock的底层默认是非公平锁:(假如一个3s执行完,一个3小时执行完,如果用公平锁,3s的要等3小时)

 

 

 公平锁:不能插队

非公平锁:可以插队

 

 

 

 传统的锁Synchronized:

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

        // @FunctionalInterface 函数式接口。
        /*
        匿名内部类,写起来比较繁琐,直接用lambda表达式 (参数)->{代码}  ()是从方法体开始的
        new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();*/
        new Thread(()->{   // 多线程
            for (int i = 1; i < 20; i++) {  // 操作:把资源类丢入线程
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 1; i < 20; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 1; i < 20; i++) {
                ticket.sale();
            }
        },"C").start();


    }
}

// 资源类 用oop思想
  class  Ticket {
    // 属性方法
    private int number = 30;
    // 卖票的方式
    // synchronized本质:队列,锁
    public synchronized void sale() {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出第" + (number--) + "张票" + "还剩" + number);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

lock锁:

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

// 基本的卖票例子
/*
 * 真正的多线程开发,公司中的开发,要降低耦合性
 * 线程就是一个单独的资源类,没有任何附属的操作
 * 1.属性 2、方法
 * */
public class SaleTicketDemo02 {
    public static void main(String[] args) {
        // 并发:多线程操作同一个资源类
        Ticket ticket = new Ticket();  // 资源类
        new Thread(()->{for (int i = 1; i < 20; i++) ticket.sale(); },"A").start();
        new Thread(()->{for (int i = 1; i < 20; i++) ticket.sale(); },"B").start();
        new Thread(()->{for (int i = 1; i < 20; i++) ticket.sale(); },"C").start();

    }
}

// Lock三部曲
/*
1:new ReentrantLock();
2:加锁lock.lock();
3:解锁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);
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             lock.unlock();
         }



    }
}

 

思考:lock锁和synchronized有什么区别?(记住4-5个)(想象成自动挡和手动挡)

1:synchronized是一个关键字,而lock是一个类

2:synchronized适合少量的代码,而lock适合大量的代码块

3:synchronized是自动的加锁解锁,而lock需要手动加锁解锁

4:synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等) lock不一定傻傻的等下去,它会尝试获取锁trylock()

5:synchronized无法获取锁的状态,而lock可以判断是否获取了锁

6:synchronized 可重入锁,不可中断的,非公平   lock 可重入锁,可以判断锁,非公平(可以自己设置)

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

 

传统的生产者和消费者问题,虚假唤醒

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();

        }
        Thread.sleep(100);
        number++; // 业务
        System.out.println(Thread.currentThread().getName() + " => " + number);
        // 通知其它线程我+1加完了
        this.notifyAll();

    }


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

两个线程的时候还正常,四个进程之后就乱套了

 

 问题解决:

 

 

// 生产者消费者口诀
// 判断等待,业务,通知
class Data{
    private int number = 0;

    // +1
    public synchronized void increment() throws InterruptedException {
       while (number != 0) {
            // 等待
            this.wait();

        }
        Thread.sleep(100);
        number++; // 业务
        System.out.println(Thread.currentThread().getName() + " => " + number);
        // 通知其它线程我+1加完了
        this.notifyAll();

    }


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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2021-06-06 23:26  Love&Share  阅读(43)  评论(0编辑  收藏  举报

导航