1. 多线程的概念:
如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程”多个线程交替占用CPU资源,而非真正的并行执行。
2. 多线程好处:
(1)充分利用CPU的资源
(2)简化编程模型
(3)带来良好的用户体验
3. 主线程:
main()方法即为主线程入口产生其他子线程的线程必须最后完成执行,因为它执行各种关闭动作
4.在Java中创建线程的两种方式
(1)继承java.lang.Thread类
(2)实现java.lang.Runnable接口
定义线程 创建线程对象 启动线程 终止线程
5. 继承Thread类创建线程
(1)步骤:
定义MyThread类继承Thread类
重写run()方法,编写线程执行体
public class Test11 {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
MyThread mt2 = new MyThread();
mt1.start();
mt2.start();
}
}
class MyThread extends Thread{
@Override
public void run() {
for (int i = 1; i <=20; i++) {
System.out.println("你好 ,"+ Thread.currentThread().getName());
}
}
}
(2)直接结果分析:
多个线程交替执行,不是真正的“并行”线程每次执行时长由分配的CPU时间片长度决定
并行: 两个程序都执行,同时进行,抢占CPU资源。
并发: 做完一件事,立马在做另一件事,称为并发。
6. 启动线程调用 线程对象的start 方法,和run方法的区别
调用start() :子线程执行run()方法多条执行路径,主线程和子线程并行交替执行
调用run() :主线程执行run()只有主线程一条执行路径
7. 实现Runnable接口创建线程
步骤:
定义MyRunnable类实现Runnable接口
实现run()方法,编写线程执行体
public class Test3 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable(); //创建实现了线程接口的对象。
Thread t = new Thread(mr); //创建线程对象,把线程接口对象传递
t.start(); //开启线程。
}
}
class MyRunnable implements Runnable{ //创建MyRunnable类,实现Runnable接口
@Override
public void run() { //重写run方法
for (int i = 0; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() +"---" + i);
}
}
}
8. 比较两种创建线程的方式
继承Thread类:
编写简单,可直接操作线程适用于单继承
实现Runnable接口:
避免单继承局限性,便于共享资源推荐使用实现Runnable接口方式创建线程
9. 线程中,常见的线程调度方法:
线程调度指按照特定机制为多个线程分配CPU的使用权
(1)setPriority(int newPriority) 更改线程的优先级
线程优先级由1~10表示,1最低,默认优先级为5,优先级高的线程获得CPU资源的概率较大
(2)static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
让线程暂时睡眠指定时长,线程进入阻塞状态,睡眠时间过后线程会再进入可运行状态
(3)millis为休眠时长,以毫秒为单位
调用sleep()方法需处理InterruptedException异常
(4)void join() 等待该线程终止
使当前线程暂停执行,等待其他线程结束后再继续执行本线程
(5)join(millis)
millis:以毫秒为单位的等待时长
nanos:要等待的附加纳秒时长
需处理InterruptedException异常
(6)static void yield() 暂停当前正在执行的线程对象,并执行其他线程
暂停当前线程,允许其他具有相同优先级的线程获得运行机会
该线程处于就绪状态,不转为阻塞状态
(7)void interrupt() 中断线程
(8) boolean isAlive() 测试线程是否处于活动状态
(9)Thread.currentThread() 获取当前线程对象
(10)getName() 获取线程名字
(11)setName() 设置线程名字
10. 守护线程 setDaemon()
守护线程,不会单独执行,当被守护的线程执行完,那么守护线程也就不再单独执行,发现了就结束
11. 实现代码同步的两种方式
(1)用同步代码块的形式实现
语法:synchronized(锁对象){
希望被同步的代码;
}
锁对象: 可以是任何一个类的对象,但是不能是匿名对象。
通常,可以 用一个 this ,this 代表当前类对象
但是注意,如果多个线程子对象操作一个需要同步的代码块的时候this 不是同一个锁对象,所以不能产生同步效果
常用的三种锁对象:
this 当前类对象。
随便创建一个类的对象用。当前类的字节码对象,有且只有一个(推荐使用)
(2) 通过执行被synchronized 修饰的方法,来实现同步。
在方法的权限修饰词后面 加上 synchronized 即可。
同步方法,用的锁对象,是this
12.多线程共享数据的实现
变量,被static 修饰,进入常量池,就不会重复创建。这样几个子线程,即会共享该变量
13. 多线程操作中,锁对象,产生死锁的问题
在多线程嵌套的 代码情况下,如果用了相同的锁对象,那么就会出现互斥锁,也称死锁的问题,有可能无法同步。所以开发中,一定要注意使用锁对象,避免死锁问题出现