线程与进程
- 进程:每一个进程的内存空间是独立的,互不共享
- 线程:进程中的一个执行路径,多个线程之间共享一个内存,线程之间能够自由切换,并发执行(同一时刻执行)
- 一个进程启动之后,又可以划分为多个线程
- 多线程是能让线程更合理的交替进行,提高cpu的使用率,而不是提高运行速度
线程的调度
- 分时调度:把cpu时间均分,轮流使用
- 抢占式调度:优先让优先级高的线程使用cpu,如果相同,则随机使用 ,优先级越高,抢到cpu的概率越高
- 1000个人同时去分cpu没有1000人排队快,因为切换的时间很长
同步与异步
- 同步:排队执行,效率低但是安全
- 异步:同时执行,效率高但是数据不安全
并发与并行
- 并行是指在同一时刻同时执行,并发是指在同一时间段内同时执行
- 进程之间相互独立,可以实现并行执行,而线程之间只能是并发执行,其实就是顺执行,cpu可以按照时间切片执行,实现高速切换,
继承Thread
- 线程停止不用stop,(有可能会无法释放资源就被关闭),通过变量做标记,再return;即可
- sleep(参数毫秒) 线程休眠
- setDaemon(boolean) 设置为守护线程还是用户线程
- 守护线程:掌握不了自己,当所有用户线程死亡,他才会死亡
- 用户线程:自己决定自己死亡
Runnable
获取和设置线程名称
线程休眠
Thread.sleep(1000);
线程阻塞
线程阻塞包括所有消耗时间的操作,比如说文件读取
线程中断
线程是否中断由其自己决定
用return; 来中断
thread.interrupt();
这个可以调用run()里面的中断异常
守护线程
thread.setDaemon(true);
这样就设置守护线程(在线程启动之前设置)
线程不安全
同步代码块synchronized
上同一把锁,使用synchronized方法
同步方法
显式锁
公平锁非公平锁
公平锁:先到先得
非公平锁:一块抢
Lock l = new ReentrantLock(true);//公平锁 默认为false(非公平)
公平死锁
线程死锁是指两个或两个以上的线程互相持有对方所需要的资源,由于synchronized的特性,一个线程持有一个资源,或者说获得一个锁,在该线程释放这个锁之前,其它线程是获取不到这个锁的,而且会一直死等下去,因此这便造成了死锁。
一个锁只能被一个线程所占用,当一个线程首先获取到这个锁之后,在该线程释放这个锁之前,其它线程均是无法获取到这个锁的。
public class Demo4 { /** * 线程死锁 * @param args */ public static void main(String[] args) { Culprit c = new Culprit(); Police p = new Police(); new MyThread(c,p).start(); c.say(p); } static class MyThread extends Thread{ private Culprit c; private Police p; public MyThread(Culprit c, Police p) { this.c = c; this.p = p; } @Override public void run() { p.say(c); } } static class Culprit{ public synchronized void say(Police p){ System.out.println("罪犯:你放我,我放人质"); p.fun(); } public synchronized void fun(){ System.out.println("罪犯:答应你"); } } static class Police { public synchronized void say(Culprit c) { System.out.println("警察:你放人质,我放你"); c.fun(); } public synchronized void fun() { System.out.println("警察:答应你"); } } }
解决方法:在已经有一个锁的时候避免再调用另外的锁
多线程通信问题
Object里面的wait()
Object里面的notify()唤醒随机一个 notifyAll()唤醒全部
“sleep() 和 wait() 的区别就是 调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁”
package com.java.demo; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Demo4 { /** * 多线程通信问题, 生产者与消费者问题 * @param args */ public static void main(String[] args) { Food f = new Food(); new Cook(f).start(); new Waiter(f).start(); } //厨师 static class Cook extends Thread{ private Food f; public Cook(Food f) { this.f = f; } @Override public void run() { for(int i=0;i<100;i++){ if(i%2==0){ f.setNameAndSaste("老干妈小米粥","香辣味"); }else{ f.setNameAndSaste("煎饼果子","甜辣味"); } } } } //服务生 static class Waiter extends Thread{ private Food f; public Waiter(Food f) { this.f = f; } @Override public void run() { for(int i=0;i<100;i++){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } f.get(); } } } //食物 static class Food{ private String name; private String taste; //true 表示可以生产*************************************** private boolean flag = true; public synchronized void setNameAndSaste(String name,String taste){ if(flag) { this.name = name; try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } this.taste = taste; flag = false;//表示饭菜做完而未端走,所以不能继续做菜 this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void get(){ if(!flag) { System.out.println("服务员端走的菜的名称是:" + name + ",味道:" + taste); flag = true; this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
问题解决的关键并不是添加线程安全synchronized,因为是非公平锁,关键是让厨师做饭时服务员睡着,服务员送饭时厨师睡着(厨师做完饭睡着后,服务员端菜)
线程状态Thread.start
带返回的线程Callable
之前的是一起走,这个可以一起走,也可以等待,有主次感觉
这个时候如果调用get() 则会导致系统等待callable结束
futureTask.isDone();//返回任务是否完成 futureTask.cancel();//取消任务
线程池
流程:创建线程 创建任务 执行任务 关闭线程 黑体字才是耗费时间
线程池解决了线程频繁创建导致的效率低下
定长线程池
非定长线程池会创建新的线程去执行等待的任务,而且会把一直处于空闲的线程释放掉0
后端程序本来就是多线程多缓存的
单线程:排队执行
(不)定长:并发执行
周期性的可以定时执行,而非立即执行
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo61 { /** * 缓存线程池. * (长度无限制) * 执行流程: * 1. 判断线程池是否存在空闲线程 * 2. 存在则使用 * 3. 不存在,则创建线程 并放入线程池, 然后使用 */ public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); //向线程池中 加入 新的任务 service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); } }
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo62 { public static void main(String[] args) { /** * 定长线程池. * (长度是指定的数值) * 执行流程: 3. 单线程线程池 4. 周期性任务定长线程池 * 1. 判断线程池是否存在空闲线程 * 2. 存在则使用 * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用 * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程 */ ExecutorService service = Executors.newFixedThreadPool(2); service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); } }
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Demo63 { public static void main(String[] args) { //效果与定长线程池 创建时传入数值1 效果一致. /** * 单线程线程池. * 执行流程: * 1. 判断线程池 的那个线程 是否空闲 * 2. 空闲则使用 * 4. 不空闲,则等待 池中的单个线程空闲后 使用 */ ExecutorService service = Executors.newSingleThreadExecutor(); service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); service.execute(new Runnable() { @Override public void run() { System.out.println("线程的名称:"+Thread.currentThread().getName()); } }); } }
public static void main(String[] args) { /** * 周期任务 定长线程池. * 执行流程: * 1. 判断线程池是否存在空闲线程 * 2. 存在则使用 * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用 * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程 * * 周期性任务执行时: * 定时执行, 当某个时机触发时, 自动执行某任务 . */ ScheduledExecutorService service = Executors.newScheduledThreadPool(2); /** * 定时执行 * 参数1. runnable类型的任务 * 参数2. 时长数字 * 参数3. 时长数字的单位 */ /*service.schedule(new Runnable() { @Override public void run() { System.out.println("俩人相视一笑~ 嘿嘿嘿"); } },5,TimeUnit.SECONDS); */ /** * 周期执行 * 参数1. runnable类型的任务 * 参数2. 时长数字(延迟执行的时长) * 参数3. 周期时长(每次执行的间隔时间) * 参数4. 时长数字的单位 */ service.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("俩人相视一笑~ 嘿嘿嘿"); } },5,2,TimeUnit.SECONDS); }
Lambda表达式