多线程:
概述: 进程有多条执行路径, 合成为: 多线程.
进程: 可执行程序(文件), 例如: .exe
//可以把进程理解为一辆车.
线程: 进程的执行路径(执行单元)
//可以把线程理解为: 是马路
记忆:
1. 一台电脑上可以有多个进程, 这些进程之间的数据是相互隔离的.
//例如: qq.exe, 飞秋.exe
2. 一个进程可以有多条线程, 这些线程可以共享该进程的数据.
//例如: 往QQ群共享放一个文件, 该群中的所有的用户都可以下载.
多线程并行和并发的区别是什么:
并行: 两个(多个)线程同时执行. //前提: 需要多核CPU
并发:
两个(多个)线程同时请求执行, 但是CPU同一瞬间只能执行一个线程,
于是就安排这些线程交替执行, 因为时间间隔非常短, 我们看起来好像是同时执行的, 其实不是.
多线程的实现方式:
方式一: 继承Thread类.
步骤:
1) 定义一个类(MyThread), 继承Thread类.
2) 重写Thread#run().
//重写Thread类中的run()方法.
3) 把要执行的代码放入run()方法中.
4) 在测试类中,创建线程对象.
5) 开启线程. //start()
注意事项:
A: 如果调用run()方法, 只是普通的方法调用.
B: 开启线程必须调用start()方法, 该方法会自动去调用run()方法.
C: 同一线程不能重复开启, 否则会报: IllegalThreadStateException异常.
方式二: 实现Runnable接口.
步骤:
1) 定义一个类(MyRunnable), 实现Runnable接口.
2) 重写Runnable#run().
3) 把要执行的代码放入run()方法中.
4) 在测试类中, 创建Runnable接口的子类对象,
MyRunnable mr = new MyRunnable();
并将其作为参数传入Thread类的构造, 创建线程对象.
Thread th = new Thread(mr);
5) 开启线程. //start()
方式三: 结合线程池使用(实现Callable接口). //暂时了解即可.
多线程的执行特点是什么:
随机性, 延迟性.
因为CPU在做着高效的切换.
多线程案例: 模拟卖票.
//需求: 四个窗口, 卖100张票.
出现的问题:
出现负数:if条件
出现重复值:ticket--
解决方案:
采用 同步代码块解决.
Thread类中的成员:
构造方法:
public Thread();
public Thread(String name);
public Thread(Runnable target);
public Thread(Runnable target,String name);
成员方法:
run(); //里边定义的是线程要执行的代码, 该方法会自动被start()方法调用.
start(); //开启线程, 会自动调用run().
getName();
setName();
sleep(); //休眠线程, 单位是: 毫秒.
currentThread(); //获取当前正在执行的线程对象(的引用).
同步:
概述/作用:
多线程(环境) 并发 操作同一数据, 有可能引发安全问题, 就需要用到同步解决.
分类:
同步代码块:
格式:
synchronized(锁对象) {
//要加锁的代码
}
锁对象:
1) 同步代码块的锁对象可以是任意类型的对象.
2) 必须使用同一把锁, 否则可能出现锁不住的情况.
同步方法:
静态方法:
锁对象: 该类的字节码文件对象.
非静态方法:
锁对象: this
多线程的难点(一般只在面试的时候用, 工作中基本不用)
死锁:
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的
一种阻塞的现象,若无外力作用,它们都将无法推进下去。
多线程的生命周期:
新建, 就绪, 运行(有可能发生阻塞和等待), 死亡.
扩展的知识:
1) 匿名内部类: //本质是一个对象. //记忆&掌握
内部类:
概述: 类里边还有一个类, 里边那个类叫内部类, 外边那个类叫外部类.
分类:
成员内部类: 定义在成员位置的内部类.
局部内部类: 定义在局部位置的内部类.
概述:
就是没有名字的 局部内部类.
格式:
new 类名或者接口名(){
//重写类或者接口中 所有的 抽象方法;
};
本质:
专业版: 就是一个继承了类或者实现了接口的 匿名的子类对象.
大白话: 匿名内部类不是类, 而是子类对象.
匿名内部类在实际开发中的应用:
1) 当对 对象方法(成员方法) 仅调用一次的时候.
2) 可以作为方法的实参进行传递.
个人建议:
当接口中或者抽象类中的 抽象方法仅有一个的时候, 就可以 考虑使用匿名内部类.
2) 实现Runnable接口的原理. //多态.
背景:
多线程的第一种实现方式是: 继承Thread类, 因为我们自定义的类(MyThread)是Thread类的子类,
所以MyThread类的对象调用start()方法的时候, 自动调用MyThread#run(), 这个我们可以理解,
但是MyRunnable类是实现了Runnable接口, 而Runnable接口的run()方法和Thread#start()没有关系,
问: 为什么Thread#start(), 会自动调用Runnable接口的子类(MyRunnable)中的 run()方法呢?
简化版的源码:
测试类中的代码
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread th = new Thread(mr);
th.start(); //问: 为什么会自动调用 MyRunnable#run();
}
public class Thread {
private Runnable target; //new MyRunnable();
public Thread(Runnable target) { //new MyRunnable();
this.target = target;
}
public void run() {
if(target != null) {
target.run(); //new MyRunnable().run();
}
}
}
从Eclipse贴过来的源码:
public class Thread {
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
this.target = target;
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
java基础之多线程
最新推荐文章于 2024-03-10 23:38:03 发布