📓
Be a Javaer
  • Introduction
  • 第 1 章 Java编程开发入门
    • 第 1 节 Java开发准备
    • 第 2 节 Java基本概念
    • 第 3 节 Java数据类型划分
    • 第 4 节 Java运算符
    • 第 5 节 Java程序逻辑控制
    • 第 6 节 Java方法的定义及使用
  • 第 2 章 Java面向对象编程
    • 第 1 节 类与对象
    • 第 2 节 深入分析类与对象
    • 第 3 节 数组的定义与使用
    • 第 4 节 String类的基本概念
    • 第 5 节 String类的常用方法
    • 第 6 节 this关键字
    • 第 7 节 引用传递
    • 第 8 节 数据表与简单Java类映射
    • 第 9 节 对象比较
    • 第 10 节 static关键字
    • 第 11 节 代码块
    • 第 12 节 内部类
    • 第 13 节 链表的定义与使用
    • 第 14 节 继承性
    • 第 15 节 覆写
    • 第 16 节 数组操作
    • 第 17 节 辅助概念
      • final关键字
      • 多态性
    • 第 18 节 抽象类的定义及使用
    • 第 19 节 接口的定义及使用
    • 第 20 节 Object类
    • 第 21 节 拓展概念
      • 匿名内部类
      • 包装类
    • 第 22 节 包的定义及使用
    • 第 23 节 访问控制权限
      • 单例设计模式
      • 多例设计模式
    • 第 24 节 异常的捕获及处理
    • 第 25 节 Java5新特性
      • 可变参数
      • foreach循环
      • 静态导入
    • 第 26 节 泛型
    • 第 27 节 枚举
    • 第 28 节 Annotation
    • 第 29 节 Java7新特性
      • AutoCloseable
      • Try-with-resources
    • 第 30 节 Java8新特性
      • 接口定义增强
      • Lambda表达式
      • 方法引用
      • 函数式接口
  • 第 3 章 Java高级编程
    • 第 1 节 Java多线程基础实现
    • 第 2 节 线程常用操作方法
    • 第 3 节 线程的同步与死锁
    • 第 4 节 生产者与消费者
    • 第 5 节 Java基础类库
      • StringBuffer
      • Runtime
      • System
      • finalize
      • Cleaner
      • 对象克隆
    • 第 6 节 数字操作类
      • Math类
      • Random类
      • 大数字操作类
    • 第 7 节 日期处理类
      • Date类
      • 日期格式化
      • Calendar类
    • 第 8 节 比较器
    • 第 9 节 正则表达式
      • 常用的正则标记
      • String类对正则的支持
      • java.util.regex包支持
    • 第 10 节 反射机制
    • 第 11 节 动态代理
    • 第 12 节 反射与Annotation
    • 第 13 节 国际化程序实现
    • 第 14 节 开发支持类库
      • Arrays类
      • UUID类
      • Optional类
      • ThreadLocal类
      • 定时器
      • Base64加密工具
    • 第 15 节 文件操作
    • 第 16 节 字节流与字符流
    • 第 17 节 IO辅助概念
      • 字符编码
      • 内存流
      • 管道流
      • RandomAccessFile
    • 第 18 节 打印流
    • 第 19 节 System类对IO的支持
    • 第 20 节 对象序列化
    • 第 21 节 IO高级应用
      • 缓冲输入流
      • Scanner
    • 第 22 节 网络编程
    • 第 23 节 类集框架
    • 第 24 节 List集合
    • 第 25 节 集合输出
    • 第 26 节 Map集合
    • 第 27 节 Set集合
    • 第 28 节 集合工具类
      • Stack
      • Queue
      • Properties
      • Collections工具类
    • 第 29 节 数据流Stream
    • 第 30 节 JDBC简介
    • 第 31 节 Statement接口
    • 第 32 节 PreparedStatment接口
    • 第 33 节 批处理与事务处理
  • 第 4 章 Oracle数据库基础
    • 第 1 节 Oracle简介
    • 第 2 节 Oracle安装与配置
    • 第 3 节 SQLPlus命令
    • 第 4 节 SQL简介与数据表分析
    • 第 5 节 SQL简单查询
    • 第 6 节 SQL限定查询
    • 第 7 节 查询排序
    • 第 8 节 综合练习:基础查询
    • 第 9 节 单行函数
    • 第 10 节 多表查询
    • 第 11 节 分组统计查询
    • 第 12 节 子查询
    • 第 13 节 综合案例:复杂查询
    • 第 14 节 数据更新操作
    • 第 15 节 事务处理
    • 第 16 节 数据伪列
    • 第 17 节 数据表的创建与管理
    • 第 18 节 约束的创建与管理
    • 第 19 节 综合案例:数据表操作
    • 第 20 节 序列的定义与使用
  • 第 5 章 JavaWeb基础
  • 第 6 章 走向单体地狱
  • 第 7 章 GitFlow工作流指南
    • 版本控制
    • Git
    • 集中式工作流
    • 功能分支工作流
    • GitFlow 工作流
    • Forking 工作流
    • Pull Requests
  • 第 8 章 微服务入门
    • 第 1 节 微服务简介
    • 第 2 节 Linux
    • 第 3 节 Docker
    • Docker 仓库
    • Ubuntu 安装 Docker
    • Docker 镜像加速器
    • 第 4 节 Docker Compose
    • 第 5 节 GitLab
    • 第 6 节 Nexus
    • 第 7 节 Harbor
  • 第 9 章 再谈微服务
  • 第 10 章 Spring Boot
  • 第 11 章 Spring Cloud Netflix
  • 第 12 章 Apache Dubbo Zookeeper
  • 第 13 章 Spring Cloud Alibaba
  • 第 14 章 Vue
  • 第 15 章 Kubernetes
  • 第 16 章 Spring Security oAuth2
  • 第 17 章 Flutter
  • Redis
    • Redis 入门
    • Redis 的数据类型
    • Redis 事务
    • Jedis
    • Spring Boot 整合 Redis
    • Redis 配置文件
    • Redis 持久化
    • Redis 发布/订阅
    • Redis 主从复制
    • Redis Sentinel
    • Redis 缓存故障
  • Glossary
由 GitBook 提供支持
在本页
  • 线程的命名与取得
  • 线程的休眠
  • 线程的中断
  • 线程合并
  • 线程让步
  • 线程优先级
  • 总结

这有帮助吗?

  1. 第 3 章 Java高级编程

第 2 节 线程常用操作方法


多线程有很多的方法定义,但是大部分的方法都是在Thread类里面定义的,强调几个与开发有关的方法。

线程的命名与取得

所有的线程程序的执行,每一次都是不同的运行结果,因为它会根据自己的情况进行资源抢占,如果要想区分每一个线程,那么就必须要依靠线程的名字。对于线程名字一般会在其启动之前进行定义,不建议对已经启动的线程进行更改名称,或者是为不同的线程设置重名的情况。

如果要想进行线程名称的操作,可以使用Thread类的如下方法:

  • 构造方法:public Thread(Runnable target, String name)

  • 设置名字:public final void setName(String name)

  • 取得名字:public final String getName()

对于线程名字的操作会出现一个问题,这些方法是属于Thread类里面的,可是如果在线程类(Runnable)子类,这个类里面并没与继承Thread类,如果要想取得名字,那么能够取得的就当前执行本方法的线程名字。所以在Thread类里面提供有一个方法:

  • 取得当前线程对象:public static Thread currentThread()

范例: 观察线程的命名

package com.alpha;
class MyThread implements Runnable {
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
}
public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt).start();
		new Thread(mt).start();
		new Thread(mt).start();
	}
}

如果在实例化Thread类对象的时候没有为其设置名字,那么会自动的进行编号命名,也就是说保证线程对象的名字不重复。

范例: 设置名字

package com.alpha;
class MyThread implements Runnable {
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
}
public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "自己的线程A").start();
		new Thread(mt).start();
		new Thread(mt, "自己的线程B").start();
	}
}

下面来观察如下的一个程序执行。

package com.alpha;
class MyThread implements Runnable {
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName());
	}
}
public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "自己的线程对象").start();
		mt.run();
	}
}
main
自己的线程对象

原来主方法就是一个线程(main线程),那么所有在主方法上创建的线程实际上都可以将其表示为子线程。

通过以上的代码可以发现,线程实际上一直都存在(主方法就是主线程),可是进程去哪里了呢?

每当使用java命令去解释一个程序类的时候,对于操作系统而言,都相当于启动了一个新的进程,而main只是这个新进程上的一个子线程。

**提问:**每一个JVM进程启动的时候至少启动几个线程

  • main线程:程序的主要执行,以及启动子线程;

  • gc线程:负责垃圾收集。

线程的休眠

所谓的线程休眠指的就是让线程的执行速度稍微变慢一点。休眠的方法:

  • public static void sleep(long millis) throws InterruptedException

  • public static void sleep(long millis, int nanos) throws InterruptedException

范例: 观察休眠特点

package com.alpha;
class MyThread implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 10000; i ++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ", i = " + i);
		}
	}
}
public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		new Thread(mt, "自己的线程对象A").start();
	}
}

因为每一次执行到run()方法的线程对象都必须进行休眠,所以执行的速度就会变慢。

默认情况下,在休眠的时候如果设置了多个线程对象,那么多有的线程对象将一起进入到run()方法(所谓的一起进入实际上是因为先后顺序实在是太短了,但实际上有区别。)。

线程的中断

在之前的休眠方法中抛出了一个中断异常InterruptedException,实际上线程是可以被其他线程中断的,Thread类提供以下方法:

  • 判断线程是否被中断:public boolean isInterrupted()

  • 中断线程:public void interrupt()

范例: 线程的中断

public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            System.out.println("线程休眠");
            try {
                Thread.sleep(10000);
                System.out.println("休眠结束");
            } catch (InterruptedException e) {
                System.out.println("产生中断");
            }
        });
        thread.start();
        Thread.sleep(100);
        if (!thread.isInterrupted()) {
            System.out.println("中断线程");
            thread.interrupt();
        }
	}
}

线程合并

线程合并就是将几个并发线程合并为一个单一线程执行,应用场景就是当一个线程的执行必须是要等到其他线程执行完毕之后才能执行。

  • public final void join() throws InterruptedException

  • public final void join(long millis) throws InterruptedException

  • public final void join(long millis, int nanos) throws InterruptedException

范例: 线程合并

public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 50; i ++) {
                if (i == 20) {
                    try {
                        mainThread.join();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " ==> " + i);
            }
        });
        thread.start();
        for (int i = 0; i < 50; i ++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " ==> " + i);
        }
	}
}

线程让步

如果当前线程获得CPU时间片可以使用线程让步将CPU时间片让渡给其他线程,而自身进入就绪阶段。

  • public static void yield()

范例: 线程让步

public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
        Thread mainThread = Thread.currentThread();
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 50; i ++) {
                if (i % 3 == 0) {
                    System.out.println(Thread.currentThread().getName() + " 让步");
                    Thread.yield();
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " ==> " + i);
            }
        });
        thread.start();
        for (int i = 0; i < 50; i ++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " ==> " + i);
        }
	}
}

线程优先级

所谓的优先级指的是越高的优先级,越有可能先执行。在Thread类里面提供有以下的两个方法进行优先级操作。

  • 设置优先级:public final void setPriority(int newPriority);

  • 取得优先级:public final int getPriority()。

发现设置和取得优先级都是使用了int数据类型,对于此内容有三种取值:

  • 最高优先级:public static final int MAX_PRIORITY,10;

  • 中等优先级:public static final int NORM_PRIORITY,5;

  • 最低优先级:public static final int MIN_PRIORITY,1。

范例: 测试

package com.alpha;
class MyThread implements Runnable {
	@Override
	public void run() {
		for (int i = 0; i < 20; i ++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + ", i = " + i);
		}
	}
}
public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
		MyThread mt = new MyThread();
		Thread t1 = new Thread(mt, "自己的线程对象A");
		Thread t2 = new Thread(mt, "自己的线程对象B");
		Thread t3 = new Thread(mt, "自己的线程对象C");
		t1.setPriority(Thread.MAX_PRIORITY);
		t1.start();
		t2.start();
		t3.start();
	}
}

范例: 主线程优先级是多少?

public class MainClass { // 主类
	public static void main(String[] args) throws Exception {
		System.out.println(Thread.currentThread().getPriority());
	}
}

主线程属于中等优先级。

总结

1、Thread.currentThread可以取得当前线程类对象;

2、Thread.sleep()主要是休眠,感觉是一起休眠,但实际上是有先后顺序的;

3、优先级越高的线程对象越有可能先执行。

上一页第 1 节 Java多线程基础实现下一页第 3 节 线程的同步与死锁

最后更新于5年前

这有帮助吗?