并发编程笔记(一)

并行和并发

并行:指应用能够同时执行不同的任务,可以同时执行

比如:厨房里有一个锅头,那就可以有一个厨师炒菜,如果有俩个锅头,那就可以有俩个厨师同时炒菜。

并发:描述并发不能脱离时间的描述,它指应用能够交替执行不同的任务,并不是同时执行多个任务,只不过是线程在不断的切换任务我们无法察觉到而已。

比如:描述并发就好像在说,一个厨师在一小时之内可以做出几道菜一样。

进程

指程序运行资源分配的最小单位

我们所说的资源包括:cpu,磁盘io,内存空间。同一进程中的多条线程共享该进程中的全部系统资源,进程和进程是相互独立的。进程是程序在系统的一次执行活动(比如:我们在桌面打开一个文档),程序是死的,静态的;而进程是活的,动态的。进程可以分为系统进程和用户进程:凡是为了完成操作系统的各种功能的进程就是系统进程;用户进程就是我们来启动的进程。

线程

它是cpu调度的最小单位,必须依赖于进程而存在

线程是进程的一个实体,它是比进程更小的、能独立运行的基本单位。线程是无处不在的,任何一个程序都必须要创建线程。

高并发的意义和好处:
1.可以充分利用cpu的资源
2.加快响应用户的时间
3.可以使你的代码更模块化,简单化,异步化

创建线程有几种方式?

查看Jdk官方文档明确给出答复,创建线程的方式有俩种
图片
1.继承thread类
2.实现runnable接口,

Thread和runnable的区别:
Thread是java里对线程的唯一抽象,runnable只是对任务(业务逻辑)的抽象,thread可以接受任意一个runnable的实例并运行。

线程启动

1、类名 extends Thread;然后 类.start
2、类名 implements Runnable;然后交给 Thread 运行

线程中止

stop()方法在终结线程是强制性的,它终止的时候并不一定会保证线程的资源正常释放,所以jdk不建议我们用它。

interrup()方法也可以对线程进行中断,它就好像对调用了这个方法的线程打了个招呼:你要中断了。并不代表会立马中断。Java里的线程是协作式的,不是抢占式的。线程会通过检查自身的中断标志位是否被置为true来进行响应。

isinterrupted()用来判断是否被中断,

interrupted()也可以判断当前线程是否被中断,不过同时会将中断标识位写为false。

run()和start()的区别

我们new thread类只是new 出了一个thread的实例,并没有和线程真正挂起钩来,只有执行了start方法,才真正意义上启动了线程。

Start()让一个线程进入就绪队列等待分配cpu,分配到后调用执行里面的run方法,start方法不能重复调用,不然会抛异常。

Run()方法是业务逻辑的实现,可以重复执行,也可以被单独调用。

yield()
使当前线程让出cpu占有权,但什么时候让出来不可以设定,也不会释放锁资源。【不是每个线程都需要锁的,执行yield的线程也不一定持有锁,我们也可以释放锁之后再调用yield方法】,执行到yield方法的线程会进入到就绪状态,当它分到cpu的时候再去执行。

join():
把指定的线程加入到当前线程,可以把俩个交替执行的线程合并为顺序执行。

就好像打饭排队一样,当前小王【线程a】在排队打饭,然后小王的对象【线程b】来 了,小王调用对象的join方法,那么小王的对象就先打饭,什么时候小王的对象打完 饭了,才会轮到小王。

守护线程:
被用作完成支持性工作,但是注意一点,在java虚拟机推出时daemon线程中的finally块并不一定会执行。守护线程我们一般用不到。

线程的共享

Synchronized:
可以修饰方法和同步代码块的形式来进行使用,它可以确保在同一个时刻,只有一个线程处于方法或者同步块中,保证线程对变量的访问可见性和排他性,又称为内置锁机制。

对象锁:用于对象实例方法上或对象实例上,
类锁:用于类的静态方法或者类的class对象上,

切记加锁一定要加同一把锁(同一个对象),错误的加锁会导致线程的不安全性。

volatile:
最轻量的同步机制,它保证了不同线程对这个变量进行操作时的可见性。一个线程修改了某个变量的值,对其他线程来说立即可见。

注意:volatile不能保证数据在多个线程下同事写时的安全,它比较适用的场景是一写多读。

线程的协作

线程之间的相互配合,比如:一个线程修改了一个对象的值,其他线程感知到了变化,然后进行相应的操作。相当于前者是生产者,后者是消费者。简单的办法就是一直让消费者线程不断循环检查变量,循环条件设置不满足,当满足条件时推出循环。但是会出现一些问题:
(1)无法确保及时性
(2)开销大,如果使用睡眠,睡眠时间少,可能造成消费者无法发现条件变化

等待/通知机制
wait() : 调用该方法的线程进入等待状态,只有等待其他线程的通知或被中断才会返回,调用wait方法会释放对象的锁

wait(long) :超时等待一段时间,时间是毫秒,没有通知就超时返回

wait(long,int) :对于超时时间更细粒度的控制,可以到达纳秒

notify() : 通知一个在对象上等待的线程,使其从wait方法返回,但是返回的前提是该线程获取到了对象的锁,没有获得锁的线程重新进入等待状态

notifyAll() :同事所有等待在对象上的线程

等待和通知的标准范式

等待遵循原则

  1. 获取对象的锁
  2. 如果条件不满足,那么就调用对象的wait()方法,被通知后仍然要检查条件
  3. 条件满足则执行对应的逻辑
    在这里插入图片描述
    通知原则
    1 获得对象的锁
    2改变条件
    3通知所有等待在对象上的线程
    在这里插入图片描述

在调用wait()和notify()系列方法之前,线程一定要获得对象的对象级别的锁,就是只能在同步方法或同步块中调用。进入wait()方法,当前线程释放锁。尽量使用notifyAll(),因为notify()只会唤醒一个线程。我们无法保证唤醒的线程一定就是我们需要唤醒的线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值