Java并发JUC(一)

96 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情
本文主要讲解内容:线程、进程、并行、并发的概念;wait和sleep区别;lock锁。

1. 线程、进程、并行、并发

进程:每个进程都有独立的代码和数据空间。一句话来说程序的一次执行(比如运行QQ.exe就会生成一个进程)。

线程:进程进一步细化为线程, *是一个 *程序内部的一条执行路径。 开了一个进程word,写字,自动保存(线程负责的)。

并行:(多个人一起行走)同一时刻,有多个指令在多个CPU上同时执行。

并发:(多线程操作同一个资源)同一时刻,有多个指令在单个CPU上交替执行。

2. wait和sleep的区别

sleep方法:属于Thread类中的方法; 会导致程序暂停执行指定的时间,让出cpu给其他线程,但是他的监控状态依然保持着,当指定时间到了之后,又会自动恢复运行状态;在调用sleep方法的过程中,线程不会释放对象锁。 (只会让出CPU,不会导致锁行为的改变)

wait方法:属于Object类中的方法;在调用wait方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify方法后本线程才进入对象锁定池准备。获取对象锁进入运行状态。(不仅让出CPU,还释放已经占有的同步资源锁

作用范围:wait必须在同步代码块中,而sleep可以在任何地方。

3. Lock锁

针对于卖票的例子,讲解两种synchronized和lock。(30张票,3个线程去卖,每个线程卖十张。)

传统的synchronized实现:

真正的多线程开发,公司中的开发

线程就是一个单独的资源类,没有任何附属操作!

1。属性2。方法;如资源类Ticket

public class SaleTicketDemo01 {
    public static void main(String[] args) {
        //并发:多个线程操作同一个资源类,把资源类丢入线程
        Ticket ticket = new Ticket();
        //lambda表达式
        new Thread(()->{
            for (int i = 1; i < 40; i++) {
                ticket.sale();
            }
        },"A").start();
        new Thread(()->{
            for (int i = 1; i < 40; i++) {
                ticket.sale();
            }
        },"B").start();
        new Thread(()->{
            for (int i = 1; i < 40; 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);
        }
    }
}

Lock锁方法:

Lock接口的锁默认是非公平锁。可以通过ReetranLock里面加参数来更换公平锁。

公平锁指的是多个资源按照申请顺序区获得锁,线程会直接进入队列排序,用于都是队列的第一位才能得到锁。

对于资源类oop使用Lock: 1.new ReentranLock(); 2.lock.lock();//加锁(lock.tryLock()尝试获取锁的方法) 3.finally =>lock.unlock();(try catch里面是代码逻辑与异常捕获,finally中放的是释放锁的操作)

public class SaleTicketDemo02 {
    public static void main(String[] args) {
        Ticket2 ticket2 = new Ticket2();
        new Thread(()->{for (int i = 0; i < 40; i++) ticket2.sale();},"A").start();
        new Thread(()->{for (int i = 0; i < 40; i++) ticket2.sale();},"B").start();
        new Thread(()->{for (int i = 0; i < 40; i++) ticket2.sale();},"C").start();
    }
}
class Ticket2 {
    private int number = 30;
​
    Lock lock = new ReentrantLock();
    //卖票
    public  void sale() {
        lock.lock();//加锁
//        lock.tryLock();//尝试获取锁.
        try {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余" + number);
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Synchronized和Lock的区别:

  • Synchronized内置的java关键字,无法判断获取锁的状态,会自动释放锁,(线程1获得锁并阻塞,那线程2就会一直等下去。就好比我要烧水50分钟,但是你要接水3秒钟,我接水就要等到你烧水结束才执行。)适合锁少量的代码的同步问题。
  • Lock是一个java类,可以判断获取锁的状态,需要手动释放锁,可以尝试获取锁(好比上面拿烧水接水的例子,那接水的线程就会尝试获取锁儿不会一直等下去),适合锁大量的同步代码。