java并发编程 | 线程详解

简介: java并发编程 | 线程详解进程与线程进程:操作系统在运行一个程序的时候就会为其创建一个进程(比如一个java程序),进程是资源分配的最小单位,一个进程包含多个线程线程:线程是cpu调度的最小单位,每个线程拥有各自的计数器,对战和局部变量等属性,并且能过访问共享的内存变量线程的状态java线...

java并发编程 | 线程详解
进程与线程
进程:操作系统在运行一个程序的时候就会为其创建一个进程(比如一个java程序),进程是资源分配的最小单位,一个进程包含多个线程

线程:线程是cpu调度的最小单位,每个线程拥有各自的计数器,对战和局部变量等属性,并且能过访问共享的内存变量

线程的状态
java线程的生命周期总共包括6个阶段:

初始状态:线程被创建,但是还没有调用start()方法
运行状态:java中将就绪状态和运行状态统称为运行状态
阻塞状态:线程阻塞,线程等待进入synchronized修饰的代码块或方法
等待状态:线程进入等待状态,需要调用notify()或notifyAll()进行唤醒
超时等待状态:线程进入等待状态,在指定时间后自行返回
终止状态:线程执行完毕
在某一时刻,线程只能处于其中的一个状态

线程初始化后,调用start()方法变为运行状态,调用wait(),join()等方法,线程由运行状态变为等待状态,调用notify()或notifyAll()等方法,线程由等待状态变成运行状态,超时等待状态就是在等待状态基础上加了时间限制,超过规定时间,自动更改为运行状态,当需要执行同步方法时,如果没有获得锁,这时线程状态就变为阻塞状态,直到获取到锁,变为运行状态,当执行完线程的run()方法后,线程变为终止状态

创建线程
创建线程有三种方式

继承Thread类
实现Runnable接口
实现Callable接口
继承Thread类

/**

  • @author: chenmingyu
  • @date: 2019/4/8 15:13
  • @description: 继承Thread类
    */

public class ThreadTest extends Thread{

@Override
public void run() {
    IntStream.range(0,10).forEach(i->{
        System.out.println(this.getName()+":"+i);
    });
}

public static void main(String[] args) {
    Thread thread = new ThreadTest();
    thread.start();
}

}
实现Runnable接口
/**

  • @author: chenmingyu
  • @date: 2019/4/8 15:18
  • @description: 实现Runnable接口
    */

public class RunnableTest implements Runnable {

@Override
public void run() {
    IntStream.range(0,10).forEach(i->{
        System.out.println(Thread.currentThread().getName()+":"+i);
    });
}

public static void main(String[] args) {
    Runnable runnable = new RunnableTest();
    new Thread(runnable,"RunnableTest").start();
}

}
实现Callable接口
/**

  • @author: chenmingyu
  • @date: 2019/4/8 15:23
  • @description: 实现Callable接口
    */

public class CallableTest implements Callable {

@Override
public Integer call() throws Exception {
    IntStream.range(0,10).forEach(i->{
        System.out.println(Thread.currentThread().getName()+":"+i);
    });
    return -1;
}

public static void main(String[] args) throws Exception {
    Callable callable = new CallableTest();
    FutureTask futureTask = new FutureTask(callable);
    new Thread(futureTask,"future").start();
    System.out.println("result:"+futureTask.get());
}

}
线程的暂停,恢复,停止
不安全的线程暂停,恢复,停止操作

Thread提供的过期方法可以实现对线程进行暂停suspend(),恢复resume(),停止stop()的操作

例:创建一个线程,run()中循环输出当前时间,在main()方法中对新建线程进行暂停,恢复,停止的操作

/**

  • @author: chenmingyu
  • @date: 2019/4/8 15:51
  • @description: 线程的暂停,恢复,停止
    */

public class OperationThread implements Runnable{

@Override
public void run() {
    while (true){
        try {
            TimeUnit.SECONDS.sleep(1L);
            System.out.println(Thread.currentThread().getName()+"运行中:"+LocalTime.now());
        }catch (InterruptedException e){
            System.err.println(e.getMessage());
        }
    }
}

public static void main(String[] args) throws Exception{
    Runnable runnable = new OperationThread();
    Thread thread = new Thread(runnable,"operationThread");
    /**
     * 启动,输出当前时间
     */
    thread.start();
    TimeUnit.SECONDS.sleep(3L);

    /**
     * 线程暂停,不在输出当前时间
     */
    System.out.println("此处暂停:"+LocalTime.now());
    thread.suspend();
    TimeUnit.SECONDS.sleep(3L);

    /**
     * 线程恢复,继续输出当前时间
     */
    System.out.println("此处恢复:"+LocalTime.now());
    thread.resume();
    TimeUnit.SECONDS.sleep(3L);

    /**
     * 线程停止,不在输出当前时间
     */
    thread.stop();
    System.out.println("此处停止:"+LocalTime.now());
    TimeUnit.SECONDS.sleep(3L);
}

}
输出

因为是过期方法,所以不推荐使用,使用suspend()方法后,线程不会释放已经占有的资源,就进入睡眠状态,容易引发死锁问题,而使用stop()方法终结一个线程是不会保证线程的资源正常释放的,可能会导致程序异常

安全的线程暂停,恢复,停止操作

线程安全的暂停,恢复操作可以使用等待/通知机制代替,安全的停止操作可以用线程是否被中断进行判断

安全的线程暂停,恢复(等待/通知机制)

相关方法:

方法名 描述
notify() 通知一个在对象上等待的线程,使其重wait()方法中返回,前提是该线程获得了对象的锁
notifyAll() 通知所有等待在该对象上的线程
wait() 调用该方法线程进入等待状态,只有等待另外线程的通知或被中断才会返回,调用该方法会释放对象的锁
wait(long) 超时等待一段时间(毫秒),如果超过时间就返回
wait(long,int) 对于超时时间耕细粒度的控制,可以达到纳秒
例:创建一个名为waitThread的线程,在run()方法,使用中使用synchronized进行加锁,以变量flag为条件进行while循环,在循环中调用LOCK.wait()方法,此时会释放对象锁,由main()方法获得锁,调用LOCK.notify()方法通知LOCK对象上等待的waitThread线程,将其置为阻塞状态,并将变量flag置为true,当waitThread线程再次获取对象锁之后继续执行余下代码

/**

  • @author: chenmingyu
  • @date: 2019/4/8 20:00
  • @description: wait/notify
    */

public class WaitNotifyTest {

private static Object LOCK = new Object();
private static Boolean FLAG = Boolean.TRUE;
public static void main(String[] args) throws InterruptedException{
    Runnable r = new WaitThread();
    new Thread(r,"waitThread").start();
    TimeUnit.SECONDS.sleep(1L);
    synchronized (LOCK){
        System.out.println(Thread.currentThread().getName()+"唤醒waitThread线程:"+LocalTime.now());
        /**
         * 线程状态由等待状态变为阻塞状态
         */
        LOCK.notify();
        /**
         * 只有当前线程释放对象锁,waitThread获取到LOCK对象的锁之后才会从wait()方法中返回
         */
        TimeUnit.SECONDS.sleep(2L);
        FLAG = Boolean.FALSE;
    }
}

public static class WaitThread implements Runnable {
    @Override
    public void run() {
        /**
         * 加锁
         */
        synchronized (LOCK){
            while (FLAG){
                try {
                    System.out.println(Thread.currentThread().getName()+"运行中:"+LocalTime.now());
                    /**
                     * 线程状态变为等待状态
                     */
                    LOCK.wait();
                    /**
                     * 再次获得对象锁之后,才会执行
                     */
                    System.out.println(Thread.currentThread().getName()+"被唤醒:"+LocalTime.now());
                }catch (InterruptedException e){
                    System.err.println(e.getMessage());
                }
            }
        }
        System.out.println(Thread.currentThread().getName()+"即将停止:"+LocalTime.now());
    }
}

}
输出

可以看到在mian线程调用LOCK.notify()方法后,沉睡了2s才释放对象锁,waitThread线程在获得对象锁之后执行余下代码

安全的线程停止操作(中断标识)

线程的安全停止操作是利用线程的中断标识来实现,线程的中断属性表示一个运行汇总的线程是否被其他线程进行了中断操作,其他线程通过调用该线程的interrupt()方法对其进行中断操作,而该线程通过检查自身是否被中断来进行响应,当一个线程被中断可以使用Thread.interrupted()方法对当前线程的中断标识位进行复位

例:新建一个线程,run方法中使用Thread.currentThread().isInterrupted()是否中断作为判断条件,在主线程中使用thread.interrupt()方法对子线程进行中断操作,用来达到终止线程的操作,这种方式会让子线程可以去清理资源或一些别的操作,而使用stop()方法则会会直接终止线程

/**

  • @author: chenmingyu
  • @date: 2019/4/8 20:47
  • @description: 中断
    */

public class InterruptTest {


public static void main(String[] args) throws InterruptedException {
    Runnable r = new StopThread();
    Thread thread = new Thread(r,"stopThread");
    thread.start();
    TimeUnit.SECONDS.sleep(1L);
    System.out.println(Thread.currentThread().getName()+"对stopThread线程进行中断:"+LocalTime.now());
    thread.interrupt();
}

public static class StopThread implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){
            System.out.println(Thread.currentThread().getName()+"运行中:"+LocalTime.now());
        }
        System.out.println(Thread.currentThread().getName()+"停止:"+LocalTime.now());
    }
}

}
未完待续...
原文地址https://www.cnblogs.com/cmyxn/p/10673601.html

相关文章
|
1天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
1天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。
|
1天前
|
安全 Java 程序员
Java中的多线程并发编程实践
【4月更文挑战第18天】在现代软件开发中,为了提高程序性能和响应速度,经常需要利用多线程技术来实现并发执行。本文将深入探讨Java语言中的多线程机制,包括线程的创建、启动、同步以及线程池的使用等关键技术点。我们将通过具体代码实例,分析多线程编程的优势与挑战,并提出一系列优化策略来确保多线程环境下的程序稳定性和性能。
|
2天前
|
缓存 分布式计算 监控
Java并发编程:深入理解线程池
【4月更文挑战第17天】在Java并发编程中,线程池是一种非常重要的技术,它可以有效地管理和控制线程的执行,提高系统的性能和稳定性。本文将深入探讨Java线程池的工作原理,使用方法以及在实际开发中的应用场景,帮助读者更好地理解和使用Java线程池。
|
2天前
|
存储 安全 Java
Java中的容器,线程安全和线程不安全
Java中的容器,线程安全和线程不安全
9 1
|
3天前
|
缓存 监控 Java
Java并发编程:线程池与任务调度
【4月更文挑战第16天】Java并发编程中,线程池和任务调度是核心概念,能提升系统性能和响应速度。线程池通过重用线程减少创建销毁开销,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。任务调度允许立即或延迟执行任务,具有灵活性。最佳实践包括合理配置线程池大小、避免过度使用线程、及时关闭线程池和处理异常。掌握这些能有效管理并发任务,避免性能瓶颈。
|
11天前
|
Java
Java 并发编程:深入理解线程池
【4月更文挑战第8天】本文将深入探讨 Java 中的线程池技术,包括其工作原理、优势以及如何使用。线程池是 Java 并发编程的重要工具,它可以有效地管理和控制线程的执行,提高系统性能。通过本文的学习,读者将对线程池有更深入的理解,并能在实际开发中灵活运用。
|
1月前
|
存储 Java 程序员
Java并发编程:深入理解线程池
【2月更文挑战第14天】 在现代软件开发中,高效地处理并发任务已成为提升性能和响应速度的关键。Java作为广泛使用的编程语言,其内置的并发工具特别是线程池机制,为开发者提供了强大的支持。本文将深入探讨Java线程池的核心概念、工作机制以及如何合理配置线程池以适应不同的应用场景。我们将通过理论解析与实践案例相结合的方式,使读者不仅理解线程池的工作原理,还能掌握其在复杂系统中的高效应用。
24 0
|
30天前
|
监控 Java
Java并发编程中的线程池优化技巧
在Java并发编程中,线程池扮演着至关重要的角色。本文将深入探讨如何优化Java线程池,从线程池的创建与配置、任务队列的选择、拒绝策略的制定、线程池状态的监控等多个方面进行详细阐述。通过本文的阅读,您将了解到如何合理地利用线程池,提高系统的并发性能,从而更好地应对各种并发场景。
|
12天前
|
Java
Java并发编程:深入理解线程池
【4月更文挑战第7天】在现代软件开发中,多线程编程已经成为一种不可或缺的技术。为了提高程序性能和资源利用率,Java提供了线程池这一强大工具。本文将深入探讨Java线程池的原理、使用方法以及如何根据实际需求定制线程池,帮助读者更好地理解和应用线程池技术。
15 0