继承Thread类
子类继承Thread类具备多线程能力
启动线程:子类对象.start()
不建议使用:避免OOP单继承局限性
实现Runnable接口
实现接口Runnable具有多线程能力
启动线程:传入目标对象+Thread对象.start()
推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用
线程是存在生命周期的。线程的生命周期分为5中不同的状态,由始至终分别是:
1、新建状态
处于新建状态中的线程对象,并不是一个独立的线程,无法运行,只有当被触发start方法时才会进入准备状态。新建状态是线程生命周期中的第一个状态,也是初始状态
2、准备状态
处于新建状态的线程对象,被调用了start方法,将进入准备状态;处于准备状态的线程随时都可能被系统选中进入运行状态,从而执行线程;可能同时有多个线程处于准备状态,然而究竟哪一个线程将进入运行状态,这是不确定的;
被阻塞的线程再次被唤醒时,并不会进入运行状态,而是进入准备状态,等待运行时机;
3、运行状态
处于准备状态中的线程一旦被系统选中,获得了运行时机,就会进入运行状态;在运行状态中,程序将执行线程类中run方法中的语句块;处于运行状态的线程,可以随时被设置为阻塞状态;
在单核CPU中,同一时刻只能有一个线程处于运行状态。在多核CPU中就可以多个线程同时处于运行状态,这也是多核CPU运行速度快的原因
4、等待(阻塞)状态
Java中提供了许多线程调度的方法,包括睡眠、阻塞、挂起和等待,使用这些方法都会将处于运行状态的线程调度到阻塞(等待)状态。处于阻塞状态的线程被解除后,并不会直接进入运行状态,而是进入准备状态,等待运行时机
5、死亡状态
当程序的run方法执行结束后,或程序发生异常终止运行后,线程会进入死亡状态。
6、如何创建线程对象?
1、继承Thread类
继承Thread类的子类具备了多线程的能力,重写Thread类的run方法,当线程被启动的时候,run方法中的程序就成为了一条独立的执行线程
2、实现Runnable接口
实现Runnable接口,需要实现Runnable接口中提供的run方法,当线程被启动的时候,run方法中的程序就成为了一条独立的执行线程
7、如何启动线程?
Java中对于线程后,可以保证的只是让每个线程都启动,并且会执行结果,但是无法决定多个线程中哪个先执行,哪个后执行
8、代码实例
package test1;
/**
*@author ShanHai:
*@version 创建时间:2021年8月24日 上午8:55:11
*/
public class MyThread extends Thread{
private String name;//线程的名字
public MyThread(String name){
this.name=name;
}
@Override
public void run() {//run方法中就是该线程要处理的功能
for(int i=0;i<=100;i++){
System.out.println(this.name+"===="+i);
}
}
}
package test1;
/**
*@author ShanHai:
*@version 创建时间:2021年8月24日 上午8:59:58
*/
public class Test1 {
public static void main(String[] args) {
//1、实例化我的线程对象
MyThread mt1=new MyThread("我的线程1");//定义一个线程
MyThread mt2=new MyThread("我的线程2");
MyThread mt3=new MyThread("我的线程3");
MyThread mt4=new MyThread("我的线程4");
//2、让线程进入准备状态
mt1.start();
mt2.start();
mt3.start();
mt4.start();
}
}
9、如何控制(调度)线程?
1、睡眠的方法
当线程处于运行状态时,调用sleep方法将使线程从运行状态进入阻塞状态,从而使程序中断运行。该方法是使正在运行的线程让出CPU最简单的方法之一
2、让步的方法
Yield方法可以使当前正在运行的线程让出当前CPU,使线程由运行状态回到准备状态,让其他线程有进入运行状态的机会;然而将CPU让给哪一个线程是不确定的
10、代码实例
package test2;
/**
*@author ShanHai:
*@version 创建时间:2021年8月24日 上午9:11:59
*/
public class MyThread implements Runnable{
private String name;
public MyThread(String name) {
super();
this.name = name;
}
@Override
public void run() {
for(int i=0;i<=100;i++){
System.out.println(this.name+"====="+i);
if(i==30){
// try {
// Thread.sleep(3*1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
Thread.yield();
}
}
}
}
package test2;
/**
*@author ShanHai:
*@version 创建时间:2021年8月24日 上午9:15:21
*/
public class Test {
public static void main(String[] args) {
//实例化MyThread对象
MyThread mt1=new MyThread("我的线程1");
MyThread mt2=new MyThread("我的线程2");
MyThread mt3=new MyThread("我的线程3");
//创建线程对象
Thread t1=new Thread(mt1);
Thread t2=new Thread(mt2);
Thread t3=new Thread(mt3);
//启动线程
t1.start();
t2.start();
t3.start();
}
}
Synchronized 和 Lock的区别
- Synchronized 内置的Java关键字,Lock是一个java类;
- Synchronized 无法判断获取锁的状态,Lock可以判断是否获取到了锁;
- Synchronized 会自动释放锁,Lock必须要手动释放锁!如果不释放锁,会死锁;
- Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去;
- Synchronized 可重入锁,不可以中断的,非公平;Lock,可重入锁,可以判断锁,非公平(可以自己设置);
- Aynchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码!