进程:一个系统中可以“同时”运行多个程序,一个程序就是一个进程
线程:一个程序中可以“同时”运行多个功能,一个功能就是一个线程
一个线程中可以“同时”运行多个其他线程
单核CPU 同一时间只能执行一个程序(一个进程中某个一个线程)
轮转时间片
多线程的创建方式(重要)
2种方式 类的对象就是一个多线程的对象
(1)某个类继承Thread类
(2)某个类实现Runnable接口,并实现其中的run方法
线程的生命周期
多线程的启动不能调用run方法,如果通过调用run方法来执行多线程,这个就是普通方法
启动多线程需要调用Thread类中start方法,start方法会以多线程的方式启动run方法
参照图片理解
多线程的控制
线程的休眠 -- 属于一种阻塞事件,让某个线程休眠一段时间
Thread.sleep(1000);让代码所属方法休眠1000ms
利用Runnable创建线程对象时的问题
如何启动线程?
Runnable r1 = new Runnable();
Thread t1 = new Thread(r1);
t1.start(); -- 相当于启动了r1
使用Thread类还是Runnable接口创建多线程类,哪一种方式更好?
Thread类的优势:提供了操作线程的方法,可以直接使用(比如start和stop)
Runnable接口的优势: 由于Java是单继承,Runnable不占据父类的位置,可以提供更好扩展性
个人认为Runnable更好,对系统来说提供了更好的扩展性
同步与异步
线程不安全的产生原因
多个线程操作同一个资源时,操作过程中让出CPU执行权,此时数据处于修改不完善的状态,
下一个线程在进行操作时读取了没有修改完善的数据,造成了数据的错误
解决线程安全的主要方法是通过 同步关键字(也被称为锁) -- synchronized
synchronized可以修饰 方法和代码块,这样的方法或代码块中的代码,只允许一个线程完整访问后才可以交给下一个线程
同步方法:不明确锁定资源,锁定了整个方法的代码
同步块:可以明确指定锁定的资源,只同步需要同步的部分代码而不是整个方法
推荐使用同步块解决线程不安全的问题
使用了synchronized的代码被称为同步方式 -- 同一时间内某方法只能被一个对象使用
没有使用synchronized的多线程代码被称为异步方式 -- 同一时间内某方法可能被多个对象同时使用
在懒汉式单例中getInstance方法应该是一个线程安全的方法,否则多线程的环境中有可能单例对象被不同线程初始化多次
在Java中对比两种单例模式,个人推荐使用饿汉式单例
死锁
共享资源 A B A+B资源都获得以后才能完成目标
线程1 获得了A资源, 需求B
线程2 获得了B资源, 需求A 程序出现相持局面 -- 死锁
解决死锁:将资源A和B作为一个整体C,将C加锁相当于直接锁定了A和B,不会出现死锁问题了
尽可能的避免出现synchronized代码块嵌套,就有出现死锁的风险
wait和notify
wait与sleep的区别?(重要)
wait是让访问某个共享资源处于等待状态,wait方法必须在同步块或同步方法中使用
wait方法是继承自Object类
某个线程中,调用了共享资源的wait方法时,该线程会让出CPU的执行权和共享资源的锁
sleep是Thread类中的方法,让调用了该方法的线程处于休眠状态(占着CPU睡觉),不会释放其占有的锁
wait与notify
wait和notify都必须在同步块或同步方法中使用,如果不是程序会报异常
wait让调用某个共享资源的线程处于等待状态
notify对调用某个共享资源的线程进行唤醒,等待->就绪
nofifyAll 对所有等待共享资源的线程同时进行唤醒 多个线程进入就绪 -> 竞争
生产者与消费者模式(了解)
有n个生产线程负责生产某类产品,存入到一个空间中
有n个消费线程负责消费某类产品,从上述空间中取得
空间 -- 共享资源
生产者 -- 负责向共享资源存放内容的线程
消费者 -- 负责从共享资源取出内容的线程
线程:一个程序中可以“同时”运行多个功能,一个功能就是一个线程
一个线程中可以“同时”运行多个其他线程
单核CPU 同一时间只能执行一个程序(一个进程中某个一个线程)
轮转时间片
多线程的创建方式(重要)
2种方式 类的对象就是一个多线程的对象
(1)某个类继承Thread类
(2)某个类实现Runnable接口,并实现其中的run方法
线程的生命周期
多线程的启动不能调用run方法,如果通过调用run方法来执行多线程,这个就是普通方法
启动多线程需要调用Thread类中start方法,start方法会以多线程的方式启动run方法
参照图片理解
多线程的控制
线程的休眠 -- 属于一种阻塞事件,让某个线程休眠一段时间
Thread.sleep(1000);让代码所属方法休眠1000ms
利用Runnable创建线程对象时的问题
如何启动线程?
Runnable r1 = new Runnable();
Thread t1 = new Thread(r1);
t1.start(); -- 相当于启动了r1
使用Thread类还是Runnable接口创建多线程类,哪一种方式更好?
Thread类的优势:提供了操作线程的方法,可以直接使用(比如start和stop)
Runnable接口的优势: 由于Java是单继承,Runnable不占据父类的位置,可以提供更好扩展性
个人认为Runnable更好,对系统来说提供了更好的扩展性
同步与异步
线程不安全的产生原因
多个线程操作同一个资源时,操作过程中让出CPU执行权,此时数据处于修改不完善的状态,
下一个线程在进行操作时读取了没有修改完善的数据,造成了数据的错误
解决线程安全的主要方法是通过 同步关键字(也被称为锁) -- synchronized
synchronized可以修饰 方法和代码块,这样的方法或代码块中的代码,只允许一个线程完整访问后才可以交给下一个线程
同步方法:不明确锁定资源,锁定了整个方法的代码
同步块:可以明确指定锁定的资源,只同步需要同步的部分代码而不是整个方法
推荐使用同步块解决线程不安全的问题
使用了synchronized的代码被称为同步方式 -- 同一时间内某方法只能被一个对象使用
没有使用synchronized的多线程代码被称为异步方式 -- 同一时间内某方法可能被多个对象同时使用
在懒汉式单例中getInstance方法应该是一个线程安全的方法,否则多线程的环境中有可能单例对象被不同线程初始化多次
在Java中对比两种单例模式,个人推荐使用饿汉式单例
死锁
共享资源 A B A+B资源都获得以后才能完成目标
线程1 获得了A资源, 需求B
线程2 获得了B资源, 需求A 程序出现相持局面 -- 死锁
解决死锁:将资源A和B作为一个整体C,将C加锁相当于直接锁定了A和B,不会出现死锁问题了
尽可能的避免出现synchronized代码块嵌套,就有出现死锁的风险
wait和notify
wait与sleep的区别?(重要)
wait是让访问某个共享资源处于等待状态,wait方法必须在同步块或同步方法中使用
wait方法是继承自Object类
某个线程中,调用了共享资源的wait方法时,该线程会让出CPU的执行权和共享资源的锁
sleep是Thread类中的方法,让调用了该方法的线程处于休眠状态(占着CPU睡觉),不会释放其占有的锁
wait与notify
wait和notify都必须在同步块或同步方法中使用,如果不是程序会报异常
wait让调用某个共享资源的线程处于等待状态
notify对调用某个共享资源的线程进行唤醒,等待->就绪
nofifyAll 对所有等待共享资源的线程同时进行唤醒 多个线程进入就绪 -> 竞争
生产者与消费者模式(了解)
有n个生产线程负责生产某类产品,存入到一个空间中
有n个消费线程负责消费某类产品,从上述空间中取得
空间 -- 共享资源
生产者 -- 负责向共享资源存放内容的线程
消费者 -- 负责从共享资源取出内容的线程