一.简介
1.进程:正在进行的程序,每一个进程执行都有一个执行顺序,该顺序是一个执行路径
2.线程:进程内部的一条执行路径或者一个控制单元
3.多线程:一个进程中有多个线程,便称为多线程
4.进程和线程的区别:
- 一个进程至少一个线程
- 进程在执行过程中拥有独立的内存单元,而多个线程共享内存
5.优势:解决了多部分运行的问题,提高了效率
6.弊端:线程太多会导致效率的降低,因为线程的执行依靠的是CPU的来回切换
二.实现方法
1.继承Thread类
- 定义一个类继承Thread类
- 复写Thread类中的public void run()方法,将线程的任务代码都封装到run方法中
- 直接创建Thread的子类对象,创建线程
- 调用start0方法,开启线程(调用线程的run方法)
- 可以通过Thread的getName0获取线程的名称
2.实现Runnable接口
- 定义一个类实现Runnable接口
- 覆盖接口中的public void run()方法将线程的任务代码都封装到run方法中
- 将runnable接口的子类对象作为参数传递给Thread类的构造函数,创建Thread类对象
- 调用start()方法,启动线程
3.区别
- 实现Runnable接口避免了单继承的局限性
- 继承Thread类线程代码存放在Thread子类的run方法中,实现Runnable接口线程代码存
- 放在接口的子类的run方法中
- 在定义线程时,建议使用实现Runnable接口,因为几乎所有多线程都可以使用这种方式实现
三.线程的几种状态
- 新建:new一个Thread对象或者其子类对象就是创建一个线程 ,但是没有开启。只是线程对象开辟了内存空间和初始化数据
- 就绪/等待:新建的对象调用start方法,就开启了线程,线程就到了就绪状态。在这个状态的线程对象,具有执行资格但并不具有执行权限
- 运行:当线程对象获取到了CPU的资源。在这个状态的线程对象,既有执行资格,也有执行权
- 阻塞/冻结:运行过程中的线程由于某些原因(此如wait,sleep),释放了执行资格和执行权。当然,可以回到运行状态,只不过并不是直接回到,而是先回到就绪状态
- 消亡/死亡:当线程对象调用的run方法结束,或者直接调用stop方法,就让线程对象死亡,在内存中变成了
四.Thread方法
- getName() :返回线程的名字,默认的线程名字Thread-编号编号从0开始
- setName() :设置线程的名字
- currentThread() :获取当前运行的线程对象
- 线程优先级:public final int getPriority()返回线程的优先级。public final void setPriority(int newPriority)更改线程的优先级。
- 暂停线程:public static void yield0暂停当前正在执行的线程对象,并执行其他线程。
- 等待终止线程:public final void join(long millis) 等待该线程终止的时间最长为millis 亳秒。注意:必须要在线程启动后(start)才能使用
- 守护线程:public final void setDaemon(boolean on)将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时, Java虚拟机退出。
五.简单实例
1.继承Thread
public class MultiThreadDemo {
//继承Thread类
public static void main(String[] args) {
MyThread m = new MyThread("线程A");
MyThread m2 = new MyThread("线程B");
MyThread m3 = new MyThread("线程C");
//m2.setPriority(10);
m.start();
//m.run();
}
}
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
@Override
public void run(){
for(int i = 0;i<20;i++){
System.out.println(name+"运行,i="+i);
}
}
}
运行结果:
2.实现Runnable接口
public class MyThreadDemo2 {
//实现Runnable接口
public static void main(String[] args) {
MyThread2 mt = new MyThread2("线程A");
MyThread2 mt2 = new MyThread2("线程B");
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt2);
synchronized(t1) {
try {
// 启动“线程t1”
System.out.println(Thread.currentThread().getName()+" start t1");
t1.start();
// 主线程等待t1通过notify()唤醒。
System.out.println(Thread.currentThread().getName()+" wait()");
t1.wait(); // 不是使t1线程等待,而是当前执行wait的线程等待
System.out.println(Thread.currentThread().getName()+" continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized(t2) {
try {
// 启动“线程t1”
System.out.println(Thread.currentThread().getName()+" start t2");
t2.start();
// 主线程等待t1通过notify()唤醒。
System.out.println(Thread.currentThread().getName()+" wait()");
t2.wait(); // 不是使t1线程等待,而是当前执行wait的线程等待
System.out.println(Thread.currentThread().getName()+" continue");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//t1.setPriority(3);
//System.out.println("*"+t1.getPriority());
//System.out.println("?"+t2.getPriority());
}
}
class MyThread2 implements Runnable{
private String name;
public MyThread2 (String name){
//this.notify();
this.name = name;
}
@Override
public void run(){
for(int i = 0;i<10;i++){
System.out.println(name+"运行,i="+i);
synchronized (this) {
try {
Thread.sleep(1000); // 使当前线阻塞 1 s,确保主程序的 t1.wait(); 执行之后再执行 notify()
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" call notify()");
// 唤醒当前的wait线程
this.notify();
}
}
}
}
运行结果: