一、线程的基本概念

1.并行和并发

并行:多个CPU核心同时工作,处理不同的任务。

并发:多个任务交替使用 CPU 核心工作,以提高 CPU 利用率。

2.进程和线程

进程:程序的一次执行。由操作系统创建并分配资源,执行一个单独的任务。

进程是系统进行资源分配和调度的独立单位,每个进程都有自己的内存空间和系统资源。进程内所有线程共享堆存储空间,保存程序中定义的对象和常量池。

Windows系统中,每个运行的 Java 程序都是一个独立的进程。

线程:进程内的执行单元,不分配单独的资源,执行一个单独的子任务。

线程是进程内调度和分派的基本单位,共享进程资源。每个线程有自己的独立的栈存储空间,保存线程执行的方法以及基本类型的数据。

运行的 Java 程序内含至少一个主线程 main ,用户可以在 Java 程序中自定义并调用多个线程。 JVM 垃圾回收线程也是一个独立的线程。

二、线程的运行状态

线程除创建状态 New 和结束状态 Terminate 外,主要有以下几种运行状态:

①运行(Running) :CPU 正在执行线程。

②就绪(Runnable) :线程一切就绪,等待 CPU 执行。

运行/就绪状态 统称为可运行状态 Runnable。 Java 程序中,线程在 运行/就绪状态 之间的切换由 JVM 自动调度,开发者无法获知。线程之间的调度采用分优先级多队列时间片轮转算法。进程在执行完 CPU 时间片切换到就绪状态之前会先保存自己的状态,下次进入运行状态时再重新加载。

③阻塞(Blocked) :线程因缺少其他资源,比如请求资源被上锁而暂停执行。在获得资源后进入就绪状态。

④等待(Waitting) :线程接受了等待指令,释放资源暂停执行。在超时/接受唤醒指令后进入就绪状态。

三、线程操作实践

Runnable 接口内唯一声明了 run 方法,由 Thread 类实现。开发者在 run 方法中定义运行时线程将要执行的功能,线程开启后由Java虚拟机自动调用并执行。如果开发者主动调用 run 方法,则只会当作普通方法执行。

1.线程两种定义方法

①继承 Thread 类,重写 run 方法。

public class MyThread extends Thread {
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }
}

②实现 Runnable 接口,实现 run 方法。推荐使用,避免了单继承的局限性。

public class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

2.启动线程

Thread 类定义了 start 方法。调用 start 方法后,系统会开启一个新线程进入就绪状态:由 JVM 会自动对线程进行调度,在运行时调用并执行线程的 run 方法。一个线程只能启动一次。

①如果自定义线程类继承 Thread 类,直接启动。

public class Main {
   public static void main(String[] args) {
       MyThread t1 = new MyThread();
       MyThread t2 = new MyThread("ThreadName");
       t1.start();
       t2.start();
   }
}

②如果自定义线程类实现 Runnable 接口,则需要借助 Thread 类启动线程。

public class Main {
   public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t1 = new Thread(mythread);                   // 由系统指定默认线程名 Thread-X
       Thread t2 = new Thread(mythread, "ThreadName");     // 开发者自定义线程名 
       t1.start();
       t2.start();
   }
}

3.同时定义和启动线程

通过匿名内部类方式,我们可以实现同时定义和启动线程的简洁写法。

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable(){
            public void run(){
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
    }
}
class Test {
   public void method() {
       System.out.println(Thread.currentThread().getName());
   }
}

4.线程弹出与暂停

Thread 类定义了 yield 方法。当前线程执行到 Thread.yield() 方法,会停止运行进入就绪状态。但线程切换到就绪状态后,什么时候被 JVM 调度回运行状态开发者无法控制。

public class ThreadDemo {
    public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t1 = new Thread(mythread);              
       Thread t2 = new Thread(mythread);    
       t1.start();
       t2.start();
    }
    static class MyThread implements Runnable {
        @Override
        public void run() {
            int count = 0;
            for (int i = 0; i < 10000; i  ) {
                Thread.yield();                    // 切换到就绪状态
                count  ;
                System.out.println(count);
            }         
        }
    }
}

Thread 类定义了 sleep 方法。当前线程执行到 Thread.sleep(1000) 方法,会停止运行进入阻塞状态,但仍会保持对象锁,其他线程不可访问其资源。直到超时后进入就绪状态。调用 sleep 方法需要捕获或抛出 InterruptException 异常。

public class ThreadDemo {
    public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t1 = new Thread(mythread);              
       Thread t2 = new Thread(mythread);    
       t1.start();
       t2.start();
    }
    static class MyThread implements Runnable {
        @Override
        public void run() {
            int count = 0;
            for (int i = 0; i < 10000; i  ) {
                try{
                    Thread.sleep(1000);             // 当前线程暂停 1s
                } catch(InterruptException e){
                    e.printStackTrace();
                }
                count  ;
                System.out.println(count);
            }         
        }
    }
}

5.线程等待与唤醒

①线程等待

当前线程执行 obj.wait() 方法,线程会停止运行并释放对象锁 obj,其他线程可以访问其资源。同时线程进入 obj 对象的等待池,直到被 notify 方法唤醒进入就绪状态。调用 wait 方法需要捕获或抛出 InterruptException 异常。

wait 方法允许计时等待。当前线程执行 obj.wait(1000) 方法,计时结束后线程会被自动唤醒进入就绪状态。

②线程唤醒

当前线程执行 obj.notify() 方法,会随机从 obj 对象等待池中选择一个线程唤醒,使其进入就绪状态。但是 notify 方法不会释放当前进程的对象锁,如果该线程持有 obj 对象的锁,当前线程释放锁后被唤醒的其他线程才能被执行。如果想被唤醒线程先执行,notify 方法后添加 wait 方法释放锁。

当前线程执行 obj.notifyall() 方法,会将所有 obj 对象等待池中所有线程唤醒。

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t = new MyThread("t");
        synchronized(t) {                         // 对 t 设置对象锁
            try {
                t.start();
                System.out.println("1");
                t.wait();                         // 当前线程释放 t 锁,进入 t 对象等待池
                System.out.println("4");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    static class MyThread extends Thread {
        @Override
        public void run() {
            synchronized (this) {                 // 对 t 设置对象锁        
                Thread.sleep(1000);
                System.out.println("2");
                this.notify();                    // 随机唤醒一个 t 对象等待池中的线程
                System.out.println("3");
            }
        }
    }
}

6.线程中断

调用 t.stop() 方法可以强制终止线程 t 运行,但强制中断线程可能会造成意想不到的问题,已不推荐使用。

目前主要采用设置线程中断标志的方式,向线程发送中止信号。由线程自行终止运行:

  • 执行 t.interrupt() 方法,将线程 t 中断标志设为 true 。
  • 执行 t.isInterrupted() 方法,查看线程 t 中断标志。
  • 执行 t.interrupted() 方法,查看线程 t 中断标志然后将其设为 false 。
public class ThreadDemo {
    public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t = new Thread(mythread);              
       t.start();
       try {
            Thread.sleep(500);
        } catch (InterruptedException e) {}
       t.interrupt();                            // 设置中断标志为 true
    }
    static class MyThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                System.out.print("hello");
                if(this.isInterrupted()){        // 查看中断标志,若为 true 结束循环
                    break;
                }
            }
        }        
    }
}

到此这篇关于Java并发编程进阶之线程控制篇的文章就介绍到这了,更多相关Java线程控制内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

Java并发编程进阶之线程控制篇的更多相关文章

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  3. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  4. Java实现世界上最快的排序算法Timsort的示例代码

    Timsort 是一个混合、稳定的排序算法,简单来说就是归并排序和二分插入排序算法的混合体,号称世界上最好的排序算法。本文将详解Timsort算法是定义与实现,需要的可以参考一下

  5. Java日期工具类的封装详解

    在日常的开发中,我们难免会对日期格式化,对日期进行计算,对日期进行校验,为了避免重复写这些琐碎的逻辑,我这里封装了一个日期工具类,方便以后使用,直接复制代码到项目中即可使用,需要的可以参考一下

  6. Java设计模式之模板方法模式Template Method Pattern详解

    在我们实际开发中,如果一个方法极其复杂时,如果我们将所有的逻辑写在一个方法中,那维护起来就很困难,要替换某些步骤时都要重新写,这样代码的扩展性就很差,当遇到这种情况就要考虑今天的主角——模板方法模式

  7. Java 中 Class Path 和 Package的使用详解

    这篇文章主要介绍了Java 中 Class Path和Package的使用详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下

  8. java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源)

    这篇文章主要介绍了java SpringBoot 分布式事务的解决方案(JTA+Atomic+多数据源),文章围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下

  9. Java一维数组和二维数组元素默认初始化值的判断方式

    这篇文章主要介绍了Java一维数组和二维数组元素默认初始化值的判断方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  10. java实现emqx设备上下线监听详解

    这篇文章主要为大家介绍了java实现emqx设备上下线监听详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部