1.进程和线程区别
多进程:在操作系统中能同时运行多个任务(程序)。如电脑: 微信和网易云音乐同时运行
多线程:在同一应用程序中有多个顺序流在执行。如网易云音乐:音乐播放和歌词显示同时进行
并发:同一时间段中几个程序在同一个处理机上运行,但任一时刻点上只有一个程序在运行。
并行:同一时刻点多个程序在多个处理机上独立异步的运行。
多线程是异步的,代码的运行结果与代码执行(调用)顺序是无关的
2.实现多线程方式
在Java中实现多线程有两种手段,一种是继承Thread类,另一种就是实现Runnable接口。
(1) 继承Thread类
public class ThreadI extends Thread {
@Override
public void run() {
System.err.println("运行新线程!");
}
public static void main(String[] args) {
ThreadI threadM = new ThreadI();
// 启动新线程执行run()方法,新线程与主线程并行执行
threadM.start();
System.out.println("运行主线程!");
}
}
(2) 实现Runable接口
public class RunnableI implements Runnable {
@Override
public void run() {
System.err.println("运行新线程!" );
}
public static void main(String[] args) {
RunnableI runnableI = new RunnableI();
Thread threadX = new Thread(runnableI);
// 启动新线程执行run()方法,新线程与主线程并行执行
threadX.start();
System.out.println("运行主线程!" );
}
}
start()方法通知"线程规划器"此线程已经准备就绪,等待系统安排时间来调用Thread中的run()方法。执行start()方法的顺序不代表线程启动的顺序!
3.线程方法
(1) currentThread()
返回当前调用程序的线程信息
返回线程的名称
Thread. currentThread().getName();
返回线程的唯一标识
Thread. currentThread().getId();
Thread.currentThread()与this的区别
当线程不作为参数传入另一个线程时,this和Thread.currentThread() 代表的是同一个对象。
线程作为参数传入时,this指向传入对象,即内部线程,而Thread.currentThread()指向调用当前方法的线程对象,即外部线程。
public class ThreadIV extends Thread {
@Override
public void run() {
System.out.println("run name: " + Thread.currentThread().getName());
System.out.println("run this: " + this.getName()); // this对象指向threadIV
}
}
class ThreadVI {
public static void main(String[] args) {
ThreadIV threadIV = new ThreadIV();
Thread thread = new Thread(threadIV);
thread.setName("A");
thread.start();
}
}
运行结果:
run name: A
run this: Thread-0
源码分析:
ThreadIV threadIV = new ThreadIV();将Runnable对象保存并初始化线程名称:Thread-N;
thread.start(); 启用线程调用run方法,执行时判断Runnable对象是否存在,调用对象的run()方法
(2) isAlive()
判断线程是否处于活动状态(已经启动且尚未终止)
(3) sleep()
使当前正在执行的线程休眠(不释放锁,单位:ms) 用法:Thread.sleep(10);
(4) 停止线程
① interrupt()
interrupt() 方法是在Thread对象线程中打停止标记,并不会真的停止线程
② interrupted()
interrupted() 静态方法是测试当前线程(运行该方法的线程)是否已经中断
测试当前线程是否已经中断。线程的中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回 false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断状态前,当前线程再次中断的情况除外)。
③ isInterrupted()
isInterrupted() 方法是测试线程Thread对象是否已经是中断状态,但不清除状态标志
④ 异常/Return中断线程
调用执行interrupt()方法,根据interrupted() 方法返回的Boolean,执行throw new InterruptedException()或return;即可实现中断线程
注意:如果线程在sleep() 状态下调用interrupt()方法,则会进入catch语句,并清除停止状态值,使之变成false。
注意:
Thread对象的stop()方法:暴力停止线程(方法已废弃)
出现问题:可能出现对锁定对象释放锁,造成数据异常
Thread对象的suspend()方法暂停线程;resume()方法恢复线程的执行。
出现问题:1.造成公共的同步对象的独占,使其他线程无法访问公共同步对象
2.出现因为线程的暂停而导致数据不同步的情况
(5) yield()
yield()方法是放弃当前的CPU资源,将其让给其他的任务去去占用CPU执行时间。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
sleep()和yield()的区别:sleep()使当前线程进入停滞状态,执行sleep()的线程在指定的时间(由程序设定的)内肯定不会被执行;yield()只是使当前线程重新回到可执行状态(放弃当前的CPU资源),执行yield()的线程有可能在进入到可执行状态后马上又被执行。
4.线程优先级
CPU优先执行优先级较高的线程对象中的任务
调用Thread对象的setPriority()方法;优先级分为1~10共10个级别,默认优先级为5
线程优先级具有继承性:比如A线程启动B线程,则B线程的优先级与A是一样的。
线程优先级具有规则性:优先级高的线程总是大部分优先执行,但不代表优先级高的线程绝对优先执行。
线程优先级具有随机性:优先级较高的线程不一定总是先执行完
5.守护线程
线程分为用户线程和守护线程;守护线程是一种特殊的线程,当进程中不存在用户线程,则守护线程自动销毁;典型的守护线程:垃圾回收线程。设置守护线程:调用Thread对象的setDaemon(true) 方法
6.线程状态
线程对象在不同的运行时期有不同的状态,状态定义:State枚举类型。在调用与线程有关的方法后,会进入不同的线程状态。
NEW状态是线程实例化未执行start()方法时的状态
RUNNABLE状态是线程进入运行的状态
TERMINATED是线程被销毁时的状态
TIMED_WAITING是线程执行了sleep方法状态
BLOCKED是某一个线程在等待锁时状态
WAITING是线程执行了wait方法后的状态
public class ThreadIII extends Thread {
@Override
public void run() {
System.out.println("预计状态:RUNNABLE = " + Thread.currentThread().getState());
}
}
public class RunMain {
public static void main(String[] args) throws InterruptedException {
ThreadIII threadA = new ThreadIII();
System.out.println("预计状态:NEW = " + threadA.getState());
threadA.start();
Thread.sleep(100);
System.out.println("预计状态:TERMINATED = " + threadA.getState());
}
}
运行结果:
…
7.线程组
可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程。线程组可以批量的管理线程或线程组对象,有效地对线程或线程组对象进行操作(JVM根线程组是system)。
public class RunMain {
public static void main(String[] args) {
ThreadVI threadVI = new ThreadVI();
ThreadIV threadIV = new ThreadIV();
ThreadGroup group = new ThreadGroup("线程组α");
Thread threadA = new Thread(group, threadVI);
Thread threadB = new Thread(group, threadIV);
threadA.start();
threadB.start();
System.out.println("活跃线程数:" + group.activeCount());
System.out.println("线程组名称:" + group.getName());
}
}
在实例化ThreadGroup线程组x时如果不指定所属的线程组,则x线程组自动归到当前线程对象所属的线程组中。
当调用线程组ThreadGroup的 Interrupt方法时,可以将该组中的所有正在运行的线程批量停止。