线程常见的构造方法
一. 多线程
1.线程常见的构造方法
方法 | 说明 |
---|---|
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程对象 |
Thread (String name) | 创建线程对象并命名 |
Thread (Runnable target ,String name) | 使用Runnable对象创建线程对象并命名 |
Thread(ThreadGroup group,Runnable target) | 线程可以被用来分组管理,分好的组即为线程组 |
1.1具体使用:
public class ThreadDemo10 {
public static void main(String[] args) {
//创建线程并设置线程名称
Thread t = new Thread("线程1") {
@Override
public void run() {
//休眠线程
try {
Thread.sleep(60*60*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//启动线程
t.start();
}
}
public class ThreadDemo11 {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(60*60*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Runnable-Thread");
thread.start();
}
}
public class ThreadDemo10 {
public static void main(String[] args) {
//创建线程并设置线程名称
Thread t = new Thread("线程1") {
@Override
public void run() {
//休眠线程
try {
Thread.sleep(60*60*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
//启动线程
t.start();
}
}
1.2 线程分组使用
import java.security.acl.Group;
import java.util.Random;
public class ThreadDemo12 {
public static void main(String[] args) {
//创建一个线程分组 (女子100米比赛)
ThreadGroup group = new ThreadGroup("thread-group");
//2.定义一个公共的任务(线程的任务)
Runnable runTask = new Runnable() {
@Override
public void run() {//具体业务
//生成一个1到3秒的随机数
int num = (1 + new Random().nextInt(3));
try {
//跑了n秒到达终点
Thread.sleep(num*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("选手到达终点:" + num + "s");
}
}78
//3.线程(运动员)
Thread t1 = new Thread(group,runTask);//选手1,2,3
Thread t2 = new Thread(group,runTask);
Thread t3 = new Thread(group,runTask);
//开始
t1.start();
t2.start();
t3.start();
//所有人全部到达终点之后宣布成绩
while (group.activeCount() > 0) {
}
System.out.println("宣布比赛成绩");
}
}
2. 线程常用属性
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否守护(后台)进程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInyerrupted() |
(1). ID是线程的唯一标识,不同线程不会重复。
(2). 名称是各种调试工具用到
(3). 状态表示线程当前所处的一个情况
(4). 优先级高的线程理论上来说更容易被调度到
(5). 关于守护线程(后台线程),需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
(6).是否存活,即为run方法是否运行结束了
(7)
优先级:
ublic class ThreadDemoByPriority2 {
private final static int MAXCOUNT = 1000;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
//得到当前线程
Thread t = Thread.currentThread();
int priority = t.getPriority();//得到线程优先级
for (int i = 0; i < 1000 ; i++) {
System.out.println(t.getName() + " --优先级" + priority);
}
}
},"线程1");
t1.setPriority(Thread.MAX_PRIORITY);
Thread t2 =new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
int priority = t.getPriority();//得到线程优先级
for (int i = 0; i < 1000 ; i++) {
System.out.println(t.getName() + " --优先级" + priority);
}
}
},"线程2");
t2.setPriority(Thread.MIN_PRIORITY);
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
Thread t = Thread.currentThread();
int priority = t.getPriority();//得到线程优先级
for (int i = 0; i < 1000 ; i++) {
System.out.println(t.getName() + " --优先级" + priority);
}
}
},"线程3");
t3.setPriority(Thread.NORM_PRIORITY);
//同时启动线程
t2.start();
t1.start();
t3.start();
}
}
结论:优先级高的大概率先执行
isAlive
public class ThreadDemoByAlive {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
Thread thread = Thread.currentThread();
System.out.println("线程是否存活2: " + thread.isAlive());
});
System.out.println("线程是否存活1 " + t.isAlive());
t.start();
System.out.println("线程是否存活3 " + t.isAlive());
Thread.sleep(1000);
System.out.println("线程是否存活4 " + t.isAlive());
}
}
3. 守护线程
public class ThreadDemoByDameon {
public static void main(String[] args) throws InterruptedException {
//得到当前的线程
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + "--是否是守护线程 " + thread.isDaemon());
Thread t1 = new Thread(()->{
//得到当前线程
Thread cThread = Thread.currentThread();
System.out.println(cThread.getName() + "--是否为守护线程 " + cThread.isDaemon());
Thread tt1 = new Thread(()->{
Thread cThread2 = Thread.currentThread();
System.out.println(cThread2.getName() + "--是否为守护线程" +cThread2.isDaemon());
},"子线程的子线程1");
tt1.start();
},"子线程1");
//手动指定线程为守护线程
t1.setDaemon(true);
t1.start();//启动线程
Thread.sleep(1000);
}
}
4.守护线程 VS 用户线程
结论:
- JVM 会等待所有的用户线程执行完成后,再退出,但JVM 不会等待守护线程执行完再退出。
- 守护线程是为用户线程服务的,没有了用户线程之后,守护线程也没有存在的必要了。
区别:
用户线程在Java程序中比较重要,JVM一定要等所有的用户线程执行完后才能自然结束,而守护线程就不一样了,守护线程是为用户线程服务的,当所有的用户线程执行完后,不管守护线程是否执行,JVM都会退出执行。
二. 线程的常用方法
1. 线程等待 join——李四接班
有时,我们需要等待一个线程执行完它的工作后,才能进行自己的下一步工作。
方法 | 说明 |
---|---|
public void join() | 等待线程结束 |
public void join(long mills) | 等待线程结束,最多等待 mills 毫秒 |
public void join(long mills,int nanos) | 同理,但是可以更高精度 |
/*
* join
* */
public class ThreadByJoin {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
//1.张三开始上班
System.out.println("1.张三开始上班");
//2.张三正在上班
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.张三下班
System.out.println("3. 张三下班");
});
//启动程序
t1.start();
t1.join();
Thread t2 = new Thread(()->{
//1.李四开始上班
System.out.println("1.李四开始上班");
//2.李四正在上班
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.李四下班
System.out.println("3.李四下班");
});
t2.start();
}
}
优点:
- 写法优雅
- 运行时所用的资源更少
2. 线程的终止
2.1 使用自定义标识符终止线程
public class ThreadInterrupet {
//1.声明一个自定义标识符
private static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while (!flag){
System.out.println("正在转账....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("啊? 差点误了大事!");
});
thread.start();
Thread.sleep(3000);
//终止线程
System.out.println("有内鬼,终止交易");
flag = true;
}
}
2.2 使用 interrupt() 终止线程
public class ThreadInterrupt2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while (!Thread.interrupted()){
System.out.println("正在转账...");
}
System.out.println("险些误了大事");
});
thread.start();
Thread.sleep(100);
//终止线程
thread.interrupt();
System.out.println("有内鬼,终止交易");
}
}
interrupt() 需要配合Thread.currentThread().isInterrupted() 或 Thread.interrupted() 一块使用,从而实现线程的终止。
2.3 isinterrupted和interrupted 的区别:
- interrupted 属于静态方法,所有程序都可以直接调用的全局方法;而isinterrupted 属于某个实例的方法。
- interrupted 在使用完之后会重置终端标识符,而isinterrupted 不会中断标识符。
3. yield 让出执行权
yield:让出CPU的执行权
public class ThreadYield {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
Thread cThread = Thread.currentThread();
for (int i = 0; i < 100; i++) {
//让出CPU执行权
Thread.yield();
System.out.println("执行了线程 " + cThread.getName());
}
},"张三");
t1.start();
new Thread(()->{
Thread cThread = Thread.currentThread();
for (int i = 0; i < 100; i++) {
System.out.println("执行线程:" + cThread.getName());
}
},"李四").start();
}
}
yield 方法会让CPU的执行权,让线程调度器重新调度线程,但是还有一定的记录再一次调用到出让CPU的线程上的,这一次它就会执行线程的方法了,因为yield已经被执行过。
4.获取当前线程
方法 | 说明 |
---|---|
public static Thread currentHread(); | 返回当前线程对象引用 |
5.问题:在主线程中创建两个子线程,每个子线程中产生一个随机数,最终等待子线程执行完成之后,在主线程累计两个子线程的结果。
import java.util.Random;
public class ThreadDemo14 {
static int num1 = 0;
static int num2 = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
num1 = new Random().nextInt(10);
});
t1.start();
Thread t2 = new Thread(()->{
num2 = new Random().nextInt(10);
});
t2.start();
t1.join();
t2.join();
System.out.println("最终的结果: " + (num1 + num2));
}
}
![在这里插入图片描述](https://img-blog.csdnimg.cn/36e696a8e06d49358458707c78ff5572.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ryr5aSpIOaYn-i-sA==,size_20,color_FFFFFF,t_70 ,g_se,x_16)
6. 休眠当前线程
1)使用sleep休眠
2)使用TimeUtil 休眠
6.1 使用sleep休眠
方法 | 说明 |
---|---|
public static void sleep(long mills) throws InterruptedException | 休眠当前线程 mills毫秒 |
public static void sleep(long mills,int nanos) throws InterruptedException | 可以更高精度的休眠 |
public class ThreadSleep {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
try {
Thread.sleep(60*60*1000);
} catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("我接受到了终止执行的通知");
}
});
thread.start();
Thread.sleep(1000);
System.out.println("终止子线程");
thread.interrupt();
}
}
缺点: 休眠长时间 不好计算
6.2 使用TimeUtil 休眠
实现原理:
三. 线程状态
3.1 所有线程状态(6种)
NEW:新建状态,当线程被创建,但是未启动start方法之前的状态。
RUNNABLE: 运行状态,得到时间片运行中。Ready:就绪状态,未得到时间片。
BLOCKED: 阻塞状态,遇到锁就会造成阻塞状态等待另一个线程释放锁。
WAITING:无限期等待状态。
TIMED_WAITING: 有明确结束时间的等待状态。
TERMINATED:销毁状态,当线程结束之后就会变成此状态。
得到当前线程的状态
线程状态的转变
import java.util.concurrent.TimeUnit;
public class ThreadState {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
System.out.println("当前线程状态2: " + Thread.currentThread().getState());
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("当前线程状态:" + t1.getState());
t1.start();
//让主线程休眠1秒
Thread.sleep(1000);
System.out.println("当前线程状态3:" + t1.getState());
//等待子线程执行完
t1.join();
System.out.println("当前线程的状态4:" + t1.getState());
}
private static void printState() {
for (Thread.State item: Thread.State.values()){
System.out.println(item);
}
}
}