Java并发编程之Thread类详解

简介: Java并发编程之Thread类详解

Thread类详解:



1.线程(Thread): 是操作系统进行调度的最小单位,Java中的线程是对操作系统线程的封装。本文从线程的创建到停止结合代码和具体实例分析一下关于java线程的一些常见问题。


2.线程的创建:


(1)自己写一个类继承于java.lang.Thread类,并重写run()接口


(2)实现java.lang.Runnable接口,并传给Thread的构造函数。


//方式1
class MyThread extends Thread{
    @Override
    public void run() {
        //to do something in this thread
    }
}
//new一个Thread对象
Thread thread = new MyThread();
//方式2
class MyRunnable implements Runnable{
    @Override
    public void run() {
        //to do something in this thread
    }
}
//new一个线程对象
Thread thread = new Thread(new MyRunnable());


3.线程的启动: 线程对象提供了一个start方法,调用了start方法后,线程将被操作系统调度执行,执行时JVM会调用线程的run方法。值得注意的是:start方法不能重复调用,举个例子


Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("1");
    }
});
for(int i=0;i<10;i++){
    thread.start();
}


image.png


4.线程中断:线程对象提供了一个interrupt方法,可以对一个已经启动的线程进行中断操作。对一个线程执行interrupt操作后,有如下四种结果:


(1)如果被中断的线程正处于阻塞状态:包括阻塞于Object.wait(),Thread.join(),Thread.sleep()等方法,那么该线程将收到一个InterruptedException,同时线程的中断状态将被设置为false;


(2)如果被中断的线程阻塞于java.nio.channels.InterruptibleChannel的IO操作,那么channel将被关闭,并且该线程将的中断状态将被设置为true,同时该线程将收到一个java.nio.channels.ClosedByInterruptException;


(3)如果被中断的线程阻塞于java.nio.channels.Selector,那么阻塞的方法将立即返回,同时线程的中断状态将被设置为true;


(4)如果不是以上3种情况,那么被中断线程的中断状态将被设置为true。


Thread thread1 = new Thread(new Runnable() {
    @Override
    public void run() {
        int i=0;
        //调用interrupt()后,循环会退出吗?答案是肯定会的
        while (!Thread.currentThread().isInterrupted()){
            System.out.println(String.format("线程名称:[%s],执行第:[%s]次循环",Thread.currentThread().getName(),i+1));
            i++;
        }
    }
},"thread1");
thread1.start();
try {
    Thread.sleep(10);
} catch (InterruptedException e) {
    e.printStackTrace();
}
//中断线程
thread1.interrupt();


Thread thread1 = new Thread(new Runnable() {
    @Override
    public void run() {
        int i=0;
        //调用interrupt()后,循环会退出吗?答案是不会
        while (!Thread.currentThread().isInterrupted()){
            System.out.println(String.format("线程名称:[%s],执行第:[%s]次循环",Thread.currentThread().getName(),i+1));
            i++;
            try {
                Thread.sleep(100);//状态会被清理,循环不会终止
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println(String.format("[%s] is interrupted",Thread.currentThread().getName()));
            }
        }
        System.out.println(String.format("线程名称:[%s],执行结束",Thread.currentThread().getName()));
    }
},"thread1");
thread1.start();
try {
    Thread.sleep(10);
} catch (InterruptedException e) {
    e.printStackTrace();
}
thread1.interrupt();


5.线程休眠:Thread.sleep()方法,该方法是让当前线程休息一定的时间后,再继续执行。需要指出的是,在执行该方法后,当前线程并不会释放锁,在高并发的场景下可能会导致其他线程无法获取锁从而造成性能问题,因此要慎用该方法。


6.等待线程执行完毕:在一个线程中等待另一个线程执行完毕,只需要调用线程对象的join()方法即可


Thread thread1 = new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println(String.format("线程名称:[%s],执行第:[%s]次循环",Thread.currentThread().getName(),i+1));
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
},"thread1");
thread1.start();
try {
    thread1.join();
} catch (InterruptedException e) {
    e.printStackTrace();
}
//等thread1执行完毕,才会执行到这里
System.out.println("main thread finished successfully");


7.线程的停止:


当线程的run()方法执行完毕,线程会自然的停止。那么问题来了,怎么让一个运行状态中的线程停止呢?JDK中的Thread提供了一个静态方法stop(),不过目前已经废弃了。因为stop方法在线程停止的同时会让线程释放已经获取的锁,这会导致其他排队等待锁的线程获取锁,从而导致不可预知的情况。所以,官方已经不建议使用Thread.stop()方法了。那么,停止线程的正确姿势是什么?JDK中建议用一个自定义的变量用于标识线程是否需要退出,然后线程不断地去检查该变量从而决定要不要从run方法退出;或者调用线程对象的interrupt方法,通过中断异常来退出执行。


8.线程安全:


共享变量: 多个线程都能访问的变量,通常是静态变量或类的成员变量。为啥这两类变量是共享的啊?因为他们存放在JVM的堆上,JVM堆上的内存区域是多个线程共享的。


目录
相关文章
|
4月前
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
233 6
|
4月前
|
IDE Java 编译器
java编程最基础学习
Java入门需掌握:环境搭建、基础语法、面向对象、数组集合与异常处理。通过实践编写简单程序,逐步深入学习,打牢编程基础。
301 1
|
4月前
|
安全 前端开发 Java
从反射到方法句柄:深入探索Java动态编程的终极解决方案
从反射到方法句柄,Java 动态编程不断演进。方法句柄以强类型、低开销、易优化的特性,解决反射性能差、类型弱、安全性低等问题,结合 `invokedynamic` 成为支撑 Lambda 与动态语言的终极方案。
222 0
|
4月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
208 4
|
4月前
|
IDE JavaScript Java
在Java 11中,如何处理被弃用的类或接口?
在Java 11中,如何处理被弃用的类或接口?
276 5
|
4月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
264 1
|
4月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
359 1
|
Java 开发者
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
Java面试题:请解释内存泄漏的原因,并说明如何使用Thread类和ExecutorService实现多线程编程,请解释CountDownLatch和CyclicBarrier在并发编程中的用途和区别
200 0
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
363 1
|
Java
Java基础系列-第一章 创建Thread的6种方式和线程常用方法
读完本章节,您将掌握如何创建线程和线程的常用方法。
341 1
Java基础系列-第一章 创建Thread的6种方式和线程常用方法