开启掘金成长之旅!这是我参与「掘金日新计划 · 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类,可以判断获取锁的状态,需要手动释放锁,可以尝试获取锁(好比上面拿烧水接水的例子,那接水的线程就会尝试获取锁儿不会一直等下去),适合锁大量的同步代码。