Java 锁、线程执行顺序

  • 锁是什么 ?
  • 锁的什么?
  • 怎么加锁 ?
  • 什么时候加锁 ?
  • 怎么实现高效率加锁 ?

锁是什么?

  • java中的锁是一种线程同步机制,控制对共享资源的访问,来达到数据安全的一种工具。
  • 本质是依赖于底层的操作系统的 Mutex Lock(互斥锁)来实现。
  • synchronized通过monitor对象监视器来实现得,每个对象都有一个唯一得monitro
  • 1 ,加锁后,在代码编译后会生成 monitorentermonitorexit,在业务代码前后
  • 2 ,如果monitor 进入数为0,则进入monitor,持有 monitor,进入数设置为1,其它线程则阻塞,持由monitor得线程再进入,则进入数再+1
  • 3 ,持有monitor得线程,执行monitorexit指令后,进入数-1,为0时推出monitor对象,不再拥有,其它线程可以尝试获取monitor持有权

怎么加锁 ?

  • synchronized 关键字、Lock

什么时候加锁 ?

  • 线程是一个单独的资源类
  • 多线程则是,多个线程 争抢同一共享资源
  • 在资源竞争中,就会存在线程安全的问题,需要加锁控制

加锁线程排队-》基本表现
同步前-》Java 锁、线程执行顺序_第1张图片同步后-》 Java 锁、线程执行顺序_第2张图片

public class SaleTicketDemo {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 0; i < 30; i++) {
                ticket.sale();
            }
        },"C").start();
    }

}

//资源类
class Ticket{

    private int number=30;

    //synchronized 排队,锁 - 对象,class
    public synchronized void sale(){
        if (number>0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+number--+"票,剩余"+number);
        }
    }

}

锁的是什么?

  • 普通同步方法,锁的是方法的调用者,对象的实例,该资源类对象 P p1 = new P(); P p2 = new P(); p1与p2 方法调用时,锁的就不一样。
  • public synchronized void m1(){}
  • 静态同步方法,锁的是 资源类 对象.Class 类模板
  • public static synchronized void m1(){}

Lock 加锁

默认- 非公平锁

  • 非公平: 不一定先排队得就先有机会加锁,而是出现各种线程随意抢占得情况
  • 公平: 判断队列种是否有再排队得,如果有则按顺序排序,后来得进入队列尾部。
	private Lock lock = new ReentrantLock();

    public  void m1(){
        //加锁
        lock.lock();
        try {
            //业务代码 ...
        }catch (Exception e){
            e.printStackTrace();
        }finally {
        	//解锁
            lock.unlock();
        }
    }
  • Synchronized 适合少量代码同步,Lock适合锁大量的同步代码
  • Synchronized 内置的java关键字,Lock是一个java 类
  • Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
  • Synchronized 会自动释放锁,lock 必须要手动释放锁! 如果不释放,可能出现死锁
  • Synchronized 没有获取锁超时,会一直等待,Lock可以
  • Synchronized 可重入锁,不可中断,非公平;Lock 可重入锁,可以判断锁,非公平(可设置)

线程执行顺序控制

  • 1.Condition 精确控制通知唤醒
  • 2.join() 方法线程插队
public class C {

    public static void main(String[] args) {
        Data3 data = new Data3();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                data.printA();
            }
        },"A").start();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                data.printB();
            }
        },"B").start();

        new Thread(()->{
            for (int i = 0; i <10 ; i++) {
                data.printC();
            }
        },"C").start();
    }
}

class Data3{

    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
            //唤醒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");
            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()+"=>CCCCCCCCC");
            number =1;
            condition1.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

Java 锁、线程执行顺序_第3张图片

		Thread thread = new Thread(threadOrder::methodA1);
        thread.start();
        thread.join();
        Thread thread1 = new Thread(threadOrder::methodB1);
        thread1.start();
        thread1.join();

线程近乎同时执行

  • CountDownLatchCyclicBarrier
  • 并行流.parallelStream()
public class CountDownLatchTest implements Runnable{

    private CountDownLatch countDownLatch;

    public CountDownLatchTest(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            countDownLatch.countDown();
            System.out.println(Thread.currentThread().getName() + "启动" + System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        int count = Runtime.getRuntime().availableProcessors();
        CountDownLatch latch  = new CountDownLatch(count);
        for (int i = 0; i < count ; i++) {
            new Thread(new CountDownLatchTest(latch)).start();
        }
    }
}
public class CountDownLatchTest implements Runnable{

    private CyclicBarrier cyclicBarrier;

    public CountDownLatchTest(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        try {
            cyclicBarrier.await();
            System.out.println(Thread.currentThread().getName() + "启动" + System.currentTimeMillis());
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        int count = Runtime.getRuntime().availableProcessors();
        CyclicBarrier cyclicBarrier = new CyclicBarrier(count);
        for (int i = 0; i < count; i++) {
            new Thread(new CountDownLatchTest(cyclicBarrier)).start();
        }
    }
}

Java 锁、线程执行顺序_第4张图片

public static void main(String[] args) {
        List<Runnable> threads = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            int finalI = i;
            threads.add(new Thread(()->{System.out.println("线程"+ finalI +"执行: "+ LocalDateTime.now());}));
        }
        threads.parallelStream().forEach(e->{
            new Thread(e).start();
        });
    }

Java 锁、线程执行顺序_第5张图片

你可能感兴趣的:(JAVA基础,笔记,java,多线程)