线程、进程、多线程
及时不创建线程,也会有main线程,GC线程
1.继承Thread类
底层实现了Runnable接口
1.1 继承操作有3步
1.自定义线程类继承Thread类
2.重写run方法,编写业务
3.创建线程对象,调用start()
总结:线程开启不一定去执行,由CPU去调度执行。
2.Runnable接口
2.1 继承操作有3步
1.自定义线程类实现Runnable接口
2.重写run方法,编写业务
3.创建runnable实现类对象,创建线程对象 构造器传入开启线程,调用start()
总结: Thread和runnable都具有多线程能力,但是推荐Runnable,避免OOP(面向对象编程)单继承的局限性,使用多实现的方便性。
3.Callable接口(了解)
可以定义返回值
可以抛出异常
初识并发问题
多个线程操作一个资源情况下,线程不安全。
流程图
线程停止
1.建议线程正常停止——>利用次数,不建议死循环。
2.建议使用标志位——>设置一个标志位flag。
3.不要使用stop或者destroy等过时方法。
线程休眠sleep
模拟网络延时:放大问题的发生性。(倒计时)。
sleep时间到达后进入就绪状态。
线程礼让 yield,礼让不一定成功
让当前执行的线程暂停,但不阻塞。
运行状态转换位就绪状态
让cpu重新调度,礼让不一定成功,看CPU心情。
线程强制执行 Join(插队)
合并线程,待此线程执行完成,在执行其他线程,其他线程阻塞。
线程优先级
获取优先级
Thread.currentThread().getPriority()
设置优先级
thread.setPriority(Thread.MAX_PRIORITY);
守护线程(GC 日志 监控内存)daemon
线程分为用户线程和守护线程
虚拟机必须保护用户线程执行完毕
虚拟机不用等待守护线程完毕
线程.setDaemon(true);
例子:你心中的信仰,你活着它存在,你死了你的守护信仰也没有了。(守护线程也会终止)
线程同步 synchronized
每个线程都在自己的工作内存交互。
同步方法的弊端:锁的太多,浪费资源。
同步方法
同步块 synchronized(obj){}
同步监视器
把需要锁的obj写出,再把需要锁的代码块放入。
JUC安全类型集合
java.util.concurrent下
CopyOnWriteArrayList线程安全集合
产生死锁四个条件
1.互斥条件:一个资源每次只能被一个进程使用。
2.请求与保持条件:一个进程因请求资源而阻塞时,对资源保持不放
3.不掠夺条件:进程已获得的资源,在未使用完前,不允许掠夺。
4.循环等待条件:若干进程之间形成一个头尾相连的闭环。
lock锁(可重复锁)
final ReentrantLock lock = new ReentrantLock();
在一般放入try-catch-finally中
try中 lock .lock();加锁
finally中 lock .unlock();解锁
生产者消费者问题
这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件.
对于生产者,没有生产产品之前﹐要通知消费者等待﹒而生产了产品之后﹐又需要马上通知消费者消费
对于消费者﹐在消费之后,要通知生产者已经结束消费﹐需要生产新的产品以供消费.
在生产者消费者问题中,仅有synchronized是不够的
①ynchronized可阻止并发更新同一个共享资源,实现了同步
②ynchronized不能用来实现不同线程之间的消息传递(通信)
wait | 表示线程一直等待,直到其他线程通知,与sleep不同,会释放锁 |
---|---|
wait(long timeout) | 制定等待毫秒数 |
notify() | 唤醒一个处于等待的线程 |
notifyAll() | 唤醒一个对象上所有调用wait的线程,按照优先级 |