JUC 并发编程--01,线程,进程,经典卖票案例, juc的写法

进程: 就是一个程序, 里面包含多个线程, 比如一个QQ程序
线程: 进程中最小的调度单元, 比如 QQ中的自动保存功能

并发: 多个线程操作同一资源, 抢夺一个cpu的执行片段, 快速交替
并行: 多个线程一起执行

线程有几个状态: NEW(新) , RUNNABLE(运行) , BLOCKED(阻塞) , WAITING(无限等待) , TIMED_WAITING(超时等待) , TERMINATED(死亡)
他们之前相互转换关系:

1、新建(new):线程对象被创建后就进入了新建状态。如:Thread thread = new Thread();
2、就绪状态(Runnable):也被称为“可执行状态”。线程对象被创建后,其他线程调用了该对象的start()方法,从而启动该线程。如:thread.start(); 处于就绪状态的线程随时可能被CPU调度执行。
3、运行状态(Running):线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权限,暂时停止运行。直到线程进入就绪状态,才有机会进入运行状态。阻塞的三种情况:
----4.1)等待阻塞:通过调用线程的wait()方法,让线程等待某工作的完成。
----4.2)同步阻塞:线程在获取synchronized同步锁失败(因为锁被其他线程占用),它会进入同步阻塞状态。
----4.3)其他阻塞:通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或因异常退出了run()方法,该线程结束生命周期。

经典的卖票案例: 直接上代码

在这里 线程就是单独的 资源类, 属性--方法, 多个线程来操作同一资源, 这样写的好处是解耦

代码, synchronized 版本的经典的卖票案例

//这是一个资源类
class Ticket {
    private int num = 300;

    public synchronized void sale(){
        if (num > 0) {
            System.out.println(Thread.currentThread().getName()+"票的剩余个数为" + num--);
        }
    }


    public static void main(String[] args) {
        //多个线程操作同一资源,  这样写解耦,
        Ticket ticket = new Ticket();

        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"线程-1").start();

        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"线程-2").start();

        new Thread(()->{
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"线程-3").start();
    }
}

代码, Lock 版本的经典的卖票案例:

public class LockDemo {
    public static void main(String[] args) {
        Ticket_L tick = new Ticket_L();
        new Thread(()->{for (int i = 0; i < 40; i++) tick.sale();},"thread-1").start();
        new Thread(()->{for (int i = 0; i < 40; i++) tick.sale();},"thread-2").start();
        new Thread(()->{for (int i = 0; i < 40; i++) tick.sale();},"thread-3").start();
    }
}

//这是一个资源类, 还是卖票案例
class Ticket_L {
    private int num = 300;
    private Lock lock = new ReentrantLock();

    public void sale(){
        //先加一把锁
        lock.lock();
        try {
            if(num > 0){
                System.out.println(Thread.currentThread().getName()+"票的剩余个数为" + num--);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //释放锁
            lock.unlock();
        }
    }
}

synchronized 和 Lock 区别:
1: synchronized 内置的java关键字, Lock是一个java类
2: synchronized 不能判断获取锁的状态, Lock 可以判断是否获取到了锁,有个方法: lock.tryLock(), 来判断是否已经加了锁
3: synchronized 自动释放锁, Lock必须手动释放锁, 不释放的话,容易造成死锁
4: synchronized 是阻塞的, 比如线程1(获取到锁, 阻塞), 线程2(就等待,一直等待), Lock锁,不一定会一直等下去
5、Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以自己设置);
6、Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码!

posted @ 2020-08-10 15:51  死不了好气呦  阅读(244)  评论(0编辑  收藏  举报