JUC-线程基础回顾(一)

一、什么是线程?什么是进程

进程:

官方定义:

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础

简单理解:

进行(运行)中的程序,如打开任务管理器后中各种.exe程序

线程:

官方定义:

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

简单理解:

线程是真正执行资源调度(使程序跑起来)的主体,一个进程往往可以包含多个线程,但至少包含一个线程。

如:开一个idea进程,其中至少有—> 线程1:输入代码,线程2:自动保存

Java真的可以开启线程吗?

答案是 : 不能。查看Thread.start()源码可得知:

public synchronized void start() {
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    group.add(this);
    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}
// 本地方法,底层的C++ ,Java 无法直接操作硬件
private native void start0();

二、并发编程

2.1 并发编程:并发、并行

  • 并发(多线程操作同一个资源) CPU 一核 ,模拟出来多条线程,天下武功,唯快不破,快速交替
  • 并行(多个人一起行走) CPU 多核 ,多个线程可以同时执行; 线程池

通过java获取cpu的核数:

public class Test1 {
    public static void main(String[] args) {
        // 获取cpu的核数
        // CPU 密集型,IO密集型
        System.out.println(Runtime.getRuntime().availableProcessors());
       //输出为8
        //说明笔者电脑为八核处理器
    }
}

2.2 线程的几个状态

public enum State {
    // 新生
    NEW,
    // 运行
    RUNNABLE,
    // 阻塞
    BLOCKED,
    // 等待,死死地等
    WAITING,
    // 超时等待
    TIMED_WAITING,
    // 终止
    TERMINATED;
}

2.3 wait与sleep的区别

//Object.wait()
public final void wait() throws InterruptedException {
    wait(0);
}

//Thread.sleep()
public static native void sleep(long millis) throws InterruptedException;

来自不同的类

  • wait() 来自 Object类
  • sleep() 来自 Thread类

关于锁的释放

  • wait() 会释放锁:wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。
  • sleep() 不出让系统资源;(简单来说,就是抱着锁睡觉)

是否需要捕获异常?

  • 需要。源码都在上面写的死死的,throws InterruptedException 都不知网上随手一搜的博客说wait()

使用范围:

  • wait() 需要在同步代码块中使用

  • sleep()可以在任何地方睡

作用对象:

  • wait()定义在Object类中,作用于对象本身
  • sleep()定义在Thread 类中,作用当前线程。

方法属性:

  • wait()是实例方法
  • sleep()是静态方法 有static

三、卖票例子

3.1 synchronized 实现卖票例子

public class SaleTicket_WithSynchronized {
    public static void main(String[] args) {
        // 并发:多线程操作同一个资源类, 把资源类丢入线程
        Ticket ticket = new Ticket();
        // @FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{ 代码 }
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.saleTicket();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.saleTicket();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.saleTicket();
            }
        }, "C").start();

    }
}

//资源类 OOP:
class Ticket {
    //属性、方法
    private int number = 30;
    //卖票方法
    //用synchronized 上锁
    public synchronized void saleTicket() {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "卖出了第" + (number--) + "张票,剩余" + number + "张");
        }
    }
}

3.2 Lock实现卖票例子

Lock源码定义:

在这里插入图片描述
常用上锁语句:

Lock l = ...;
l.lock();   //加锁
try { // access the resource protected by this lock
} 
finally 
{ l.unlock(); //解锁} 

ReentrantLock 可重入锁

在这里插入图片描述
公平锁与非公平锁(简单认识,后面详解)

  • 公平锁: 非常公平, 不能够插队,必须先来后到!
  • 非公平锁:非常不公平,可以插队 (默认都是非公平)

案例

// Lock 三部曲
// 1、 new ReentrantLock();
// 2、 lock.lock(); // 加锁
// 3、 finally=> lock.unlock(); // 解锁
public class SaleTicket_WithLock {
    public static void main(String[] args) {
        // 并发:多线程操作同一个资源类, 把资源类丢入线程
        Ticket ticket = new Ticket();
        // @FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{ 代码 }
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.saleTicket();
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.saleTicket();
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 1; i < 40; i++) {
                ticket.saleTicket();
            }
        }, "C").start();

    }

}

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 + "张");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock(); // 解锁
        }
    }
}

四、Synchronized 和 Lock 区别

Java中的锁——Lock和synchronized

相比于synchronized,Lock接口所具备的其他特性

①尝试非阻塞的获取锁tryLock():当前线程尝试获取锁,如果该时刻锁没有被其他线程获取到,就能成功获取并持有锁

②能被中断的获取锁lockInterruptibly():获取到锁的线程能够响应中断,当获取到锁的线程被中断的时候,会抛出中断异常同时释放持有的锁

③超时的获取锁tryLock(long time, TimeUnit unit):在指定的截止时间获取锁,如果没有获取到锁返回false

synchronizedLock
性质Java的内置关键字,在JVM层面上Java类(接口)
锁的释放1、以获取锁的线程执行完同步代码,释放锁
2、线程执行发生异常,jvm会让线程释放锁
必须要手动释放锁,如果不释放锁,会造成死锁
锁的获取假设A线程获得锁,B线程等待。
如果A线程阻塞,B线程会一直等待
分情况而定,Lock有多个锁获取的方式:大致就是可以尝试获得锁,线程可以不用一直等待
锁状态无法判断可以判断
锁类型可重入 不可中断 非公平可重入 可判断 可公平(两者皆可,可手动设置)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值