线程与进程
- 进程:每一个进程的内存空间是独立的,互不共享
- 线程:进程中的一个执行路径,多个线程之间共享一个内存,线程之间能够自由切换,并发执行(同一时刻执行)
- 一个进程启动之后,又可以划分为多个线程
- 多线程是能让线程更合理的交替进行,提高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 {
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 {
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 {
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) {
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 效果一致.
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) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("俩人相视一笑~ 嘿嘿嘿");
}
},5,2,TimeUnit.SECONDS);
}
Lambda表达式



