下面咱们来了解下什么是多线程?
思考 : 能否在同一个Java应用程序中执行2个以上的无限循环呢?
1.1什么是多线程?
是指一个应用程序中有多个线程并发执行。
1.2并发:
通过CPU的调度算法,使用户感觉像是同时处理多个任务,但同一时刻只有一个执行流占用CPU执行。即使多核多CPU环境还是会使用并发,以提高处理效率。(切换执行)
多线程技术并不能直接提高程序的运行效率,而是通过提高CPU的使用率的方式来达到提高效率的目的。
1.3 问题 : 线程是不是越多越好呢?
线程并不是越多越好。 对于一个CPU而言,同一时刻,只能执行一个任务。同一时间段内,如果线程过多,每个线程被切到的时间就变少了。因此,
线程并不是越多越好。 (例如: 迅雷下载, 喂宝宝吃东西)
然而,咱们经常写的main方法就是一个线程(主线程)
2.1线程应该怎么创建呢?
线程的创建有两种;
方式一:继承Thread类
2.1.2 实现步骤及演示
1.自定义一个类,继承Thread类。
2.重写run()方法
3.创建线程类的对象
4.启动线程
2.1.3 代码实现:
package cn.itcast.multithread01;
public class Demo03 {
public static void main(String[] args) {
// 1. 创建一个 Test03 类的对象
Test03 t1 = new Test03("one");
t1.start();
// 2. 在创建一个 Test03 类的对象
Test03 t2 = new Test03("two");
t2.start();
// 3. main 线程的代码
while (true) {
System.out.println("main run ...");
}
}
}
// 创建线程实现方式一 : 继承 Thread 类
class Test03 extends Thread {
// 属性
private String name;
public Test03(String name) {
this.name = name;
}
// 行为
@Override
public void run() {
while (true) {
System.out.println(name + " run ...");
}
}
}
面试题:start 方法和run方法的区别?
run:仅是对象调方法,不调用系统资源开辟新线程
start:调用系统资源,开辟新线程
获取线程的名称:
Thread 类的子类 : 子类对象.getName();
非线程类 :Thread.currentThread().getName(); (重要)
方式二:实现runnable接口
2.2.1 实现步骤及演示:
1.自定义一个类,实现runnable接口。
2.重写run方法
3.创建线程任务类对象
4.创建线程对象,将任务类对象作为参数传入
5.启动线程
2.2.2 代码实现:
public class test implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
test task = new test();
Thread t1 = new Thread(task,"线程一");
Thread t2 = new Thread(task,"线程二");
t1.start();
t2.start();
}
}
实现原理:
2.2.3 为什么给thread传入runnable接口参数,就会执行run方法?
当我们创建线程对象时,我们已经将task任务类对象传递给线程对象,其作用是把task赋值给内部属性target进行储存,当我们调用Thread的start方法时,会判断target是否为null,因此target不为null,就会执行run方法。
以下是Thread源码
2.2.4 .两种实现多线程方式的对比分析
方式一:继承Thread方式
1. 优点: 可以在子类中增加新的成员变量, 使线程具有某种属性, 也可以在子类中增加新的方法, 使线程具有某种功能. 2. 缺点:由于Java不支持类的多继承, Thread 类的子类不能在扩展其他的类
方式二: 实现Runnable接口
- 避免了Java单继承带来的局限性
- 适合多个相同程序代码的线程去处理同一个资源的情况, 更灵活的实现数据的共享。
3. 线程同步问题
需求假设某航空公司有三个窗口发售某日某次航班的100张票.这时,100张票可以作为共享资源,三个售票窗口需要创建三个线程. 使用代码模拟实现.(一共100张!)
- 线程并发产生的问题和原因分析
- 现象:多个线程在操作共享的数据,并且对共享数据有修改会产生错乱的现象
- 原因:CPU在处理多个线程的时候,在操作共享数据的多条代码之间进行切换导致的
解决方案
同步代码块
- 作用 : 被同步代码块包裹的代码在任何时刻只能被一条线程访问.
- 语法 :
synchronized (锁对象) {
被包裹的代码…
}- 锁对象
- 锁对象可以是任意类型的对象.
- 必须要包装锁对象的
唯一性
.
- 注意点 : 锁对象千万不能定义在 run() 方法中, 原因是 run() 方法是被多条线程同时执行的, 因此就会创建出多个
锁对象
.- 锁对象要定义为成员属性
- 问题 : this 能保证数据安全吗?
- 可以的,只要保证当前类只有一个实例
- 注意
- 线程同步可以避免并发问题,但是同时也降低了执行效率
- 一般在修改共享资源的代码上同步(有可能并发修改的代码)
同步方法
- 语法:在方法上添加关键字synchronized
修饰符 synchronized 返回值类型 方法名(参数列表) {方法体...}
- 同步方法有锁对象,锁对象是this
- 静态同步方法中的锁对象是 类名.class
生命周期
以上写的不对的地方,请及时通知博主,谢谢!