多线程
前言
重温多线程
在每日一道面试题中到了多线程这一块儿的题目,发现自己基本功还是很不扎实,有关多线程的知识只了解个大概,其中的运行原理和细节都还只是浅尝辄止,貌似目前很多专业知识亦是如此。
自我拷问,我学这些知识到底是为了什么,如果只是简单应付学业我大可不必,如果是为了兴趣为了就业,那我应该沉下心来好好钻研。
这篇博客是我重温多线程的笔记,分享到这儿方便以后自己看的同时也希望能帮助到刚学习多线程的朋友,文章如有不足之处,欢迎指出,转载需请标明地址。
什么是多线程
线程是内部进程的一个独立执行的单元,一个进程可以同时并发多个线程,多线程指的是多个线程并发执行,多线程是多任务的一种特别形式,多线程能满足程序员编写高效率的程序来充分利用COU的资源分配,与线程相关的是进程,一个进程有一个或者多个线程,举个例子:QQ是一个进程,QQ中包含了登录,注册,QQ空间等,这些都是QQ中的线程,每条线程执行不同的任务。
多线程的好处有哪些?
- 多线程使得程序的响应速度更快,用户界面在进行其他工作时,其中的线程处于活跃状态,当需要时,CPU能够迅速调动资源启动线程任务。
- 多线程可以分别设置优先级和优化性能
- 多线程可以挺高CPU的利用率,使得资源最大化利用, 例如占用大量处理时间的任务可以通过多线程定时将处理器资源让给其他任务
并发与并行
- 并发:并发是指同一时刻多个进程/线程同时执行
- 并行:并行是指多个进程/线程在同一时间段执行
线程的生命周期
线程的生命周期包括五个阶段:新建、就绪、运行、阻塞、销毁

-
新建状态(new):就是使用new方法创建新线程对象,线程进入新建状态,例如:Thread thread=new Thread();
-
就绪状态(Runnable):就绪状态也称为可执行状态,线程对象在被创建后可通过调用start(),从而启动该线程进入就绪状态,该状态的线程,随时可被CPU调度执行。
-
运行状态(Running):线程获得CPU的资源调度可以执行,线程只能通过就绪状态进入到运行状态,run()定义线程的运行操作。
-
阻塞状态(Blocked):在运行状态下,因为某些原因线程放弃CPU的执行权,暂时或者停止执行,进入阻塞状态.比如调用sleep()、wait()、suspend()、join()等方法后线程就进入了阻塞状态,该状态下的线程可以通过线程休眠时间结束sleept()或者调用notify()、notifyAll()、interrupt()后线程再次回到就绪状态
-
销毁状态(Dead):线程因为执行完任务或者调用stop()、又或者异常终止而退出run(),该线程结束了生命周期
线程调度:
线程调度是指按照特定的机制CPU分配多少个线程执行的使用权
常用的线程方法:
start():调用start()的线程进入就绪状态,等待被调度
run():调用run()的线程,线程处于运行状态
Thread.currentThread():对当前线程对象的引用
setPriority():线程优先级
static void sleep():在规定的时间内让线程进行休眠,一般以毫秒millis为单位
join():等该线程结束
yield():暂时停止当前的线程让位给其他线程执行,其他线程执行后调用该方法的线程可再次被CPU调度
interrupt():中断线程,打断施法
isAlive():测试线程是否还活跃
线程的两种实现方式:
- 继承Thread类重写run()
- 实现Runnable接口重写run()
例子1:主线程
/**
* 主线程
*/
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t=Thread.currentThread();
System.out.println("当前线程名是:"+t.getName());
t.setName("主线程");
System.out.println("当前线程名是:"+t.getName());
}
}
例子2 继承Thread类实现主线程和子线程交替执行
/**
* 继承Thread实现线程
*/
public class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i <= 500; i++) {
// 获取当前线程的名字
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
public static void main(String[] args) {
// 创建子线程,执行子线程
MyThread1 myThread1 = new MyThread1();
myThread1.start();
myThread1.setName("我是子线程1");
//主线程和子线程交替执行
for (int i = 0; i < 500; i++) {
System.out.println("我是主线程,我执行了" + i + "次");
}
}
}
例子3:多个子线程交替执行
/**
* @Deacription TODO
* @Author d1252
* @Date 2021/5/8 15:05
**/
public class ThreadDemo2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"执行了第"+i+"次");
}
}
public static void main(String[] args) {
//创建子线程
ThreadDemo2 thread1=new ThreadDemo2();
ThreadDemo2 thread2=new ThreadDemo2();
ThreadDemo2 thread3=new ThreadDemo2();
//给子线程命名
thread1.setName("子线程1");
thread2.setName("子线程2");
thread3.setName("子线程3");
//运行线程
thread1.start();
thread2.start();
thread3.start();
}
}
例子4:通过实现Runnable接口来实现多线程
public class MyRunnable1 implements Runnable{
//MyRunnable1实现接口Runnable,重写Runnbale的方法run
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
MyRunnable1 myRunnable1=new MyRunnable1();
Thread thread1=new Thread(myRunnable1,"线程A");
Thread thread2=new Thread(myRunnable1,"线程B");
thread1.start();
thread2.start();
}
}
例子5:匿名内部类的方式实现多线程
public class ThreadDemo3 {
public static void main(String[] args) {
new Thread(){
public void run(){
for (int i = 0; i <100; i++) {
System.out.println("BBBBBBBBBBBB");
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("AAAAAAAAAAAAAAA");
}
}
}).start();
}
}
例子6:设置线程优先级
public class ThreadDemo4 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
public static void main(String[] args) {
Thread thread1=new Thread();
thread1.setName("主线程");
ThreadDemo4 threadDemo4=new ThreadDemo4();
Thread thread2=new Thread(threadDemo4);
thread2.setName("子线程");
// 启动
thread1.start();
thread2.start();
thread2.setPriority(9);
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
setPriority()是用来设置线程优先级的,理论上来说优先等级越高越容易被CPU调度,最高等级为10,最低0,但不是说设置了优先级就一定先执行该线程,只能说调度该线程的概率比其他线程要高,上面例子就是。
例子7:子线程设置join()强制加入
public class Thread_Join implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + ":" + i + "次");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Thread_Join());
thread.start();
for (int i = 1; i <= 10; i++) {
if (i == 6) {
// 当主线程执行了五次之后,主线程进入阻塞状态,子线程强制加入
thread.join();
}
System.out.println(Thread.currentThread().getName() + "运行" + ":" + i + "次");
}
}
}
例子8:线程设置yield()礼让
public class Thread_yield implements Runnable {
@Override
public void run() {
for (int i = 0; i < 50; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i + "次");
if (i == 10) {
Thread.yield();
}
}
}
public static void main(String[] args) {
Thread thread = new Thread(new Thread_yield(), "线程AAAA");
Thread thread1 = new Thread(new Thread_yield(), "线程BBBB");
thread.start();
thread1.start();
}
}
例子9:线程设置休眠sleep()
public class ThreadSleepDemo {
public static void main(String[] args) {
ThreadSleepDemo t=new ThreadSleepDemo();
t.sleepTime(5);
}
private void sleepTime(int time) {
for(int i=0;i<time;i++){
System.out.println("主线程执行了:"+(i+1)+"秒");
try {
//让线程休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}