Java多线程(一)多线程概要

这篇具有很好参考价值的文章主要介绍了Java多线程(一)多线程概要。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

多线程概要

多线程概要

什么是进程?

进程的特点:

什么是多线程

多线程编程:

 创建线程

1.继承 Thread 类

2.实现 Runnable 接口

多线程的优势

中断问题:

1. 通过共享的标记来进行沟通

2. 调用 interrupt() 方法来通知

等待一个线程-join()

多线程概要

什么是进程?

在冯诺依曼体系下,整个计算机设备分为,应用程序,操作系统,处理器(cpu),主存,I/O设备。应用程序在操作系统的调节下在处理器上进行合理的资源分配,而在其中一个运行起来的程序,就是进程。

cpu有一个概念,核心数和线程,核心为物理核心,线程为逻辑核心

而进程管理其实分为两步:

        1.描述一个进程:使用结构体或类,把一个进程有哪些信息,表示出来。

        2. 组织这些进程:使用一定的数据结构,把这些结构体/对象,放在一起。

进程的特点:
  1.   PID :每个进程需要有一个唯一的身份标识
  2.   内存指针:当前这个进程使用的内存是哪一部分,进程一旦开启,就会消耗一定的硬件资源
  3.  文件描述符:进程每次打卡一个文件,就会产生一个“文件描述符”  ,被标识了的意味着这个文件已打开。而一个进程会打开多个文件,然后呢就会把这些文件描述符放到循序表中,构成文件描述符表
  4. 进程调度:
  • 进程状态:就绪态,阻塞态,前者表示该进程已准备好,可以随时上cpu上执行,后者还需等待
  • 进程优先级:那个进程优先级高就先执行那个进程
  • 进程的上下文:就是描述了当前进程执行到哪里这样的“存档记录”,进程在离开CPU的时候就要把当前运行的中间结果存档在cpu的寄存器中,等到下次进程回来CPU上,在恢复之前的存档,从上次结果开始
  • 进程的记账信息:统计了每个进程,在CPU上执行了多久,可以作为调度的参考依据。
  • 并发和并行:指的是多个程序可以同时运行的现象,更细化的是多进程可以同时运行或者多指令可以同时运行。它们虽然都说是"多个进程同时运行",但是它们的"同时"不是一个概念。并行的"同时"是同一时刻可以多个进程在运行(处于running),并发的"同时"是经过上下文快速切换,使得看上去多个进程同时都在运行的现象,是一种OS欺骗用户的现象

内存分配:

        操作系统给进程分配的内存,是以“虚拟地址空间”的方式进行分配。

什么是多线程

之前说过,进程是一个运行程序,然而一个程序内的功能有很多个,而这其中就有一个问题,就是客户可能会同时用一个程序的多个功能。诺是按照以前我们的写发就是一个main方法,去实现一个主要功能,肯定是不行的。为了应对这个情况,多线程运行就在所难免。

需求决定技术发展

线程是更轻量的的进程。约定一个进程可以包含多个线程,此时多个线程每个线程都是一个独立可以调度执行的执行流(并发),这些线程公用同一份进程的系统资源。

  1. 创建线程比创建进程更快.
  2. 销毁线程比销毁进程更快.
  3. 调度线程比调度进程更快.

可以理解为,一个工厂(进程),中有很多个生产线:(线程)(调用同一份资源,内存空间,文件描述符)。

Java多线程(一)多线程概要,linux,java,服务器

其中几个问题要重点理解。一个厂子也就意味着资源和场地是一定的,如果为了生产效率,盲目去增加生产线,不去顾忌这些,反而会使的整个生成效率变慢。同理一个主机的核心也是有限,所以增加的线程数和进程数也是有限度。而一台主机到限度了,就可以增加另一台主机,从而使得核心数增加(也就是分布式处理)。

进程和线程的区别:

1.进程包含线程

2.进程有自己独立的内存空间和文件描述符,同一个进程的多个线程之间,共享同一份地址空间和文件描述符

3.进程是操作系统资源分配的基本单位,线程是操作系统调度的基本单位

4.进程之间具有独立性,一个进程挂了,不会影响到别的进程;同一个进程里的多个线程之间,一线程挂了,可能会把整个进程带走,会影响到其他线程的。

多线程编程:

Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装。

操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库)

这是我们第一个多线程。

public class ThreadDemo {
    private static class MyThread extends Thread {
        @Override
        public void run() {
            Random random = new Random();
            while (true) {
                // 打印线程名称
                System.out.println(Thread.currentThread().getName());
                try {
                    // 随机停止运行 0-9 秒
 Thread.sleep(random.nextInt(10));
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
           }
       }
   }
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
        Random random = new Random();
        while (true) {
            // 打印线程名称
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(random.nextInt(10));
           } catch (InterruptedException e) {
                // 随机停止运行 0-9 秒
                e.printStackTrace();
           }
       }
   }
}
 创建线程
1.继承 Thread
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
   }
}

  创建一个线程实例

MyThread t = new MyThread();

   调用 start 方法启动线程

t.start(); // 线程开始运行
2.实现 Runnable 接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
   }
}

创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数

Thread t = new Thread(new MyRunnable());

调用start方法

t.start(); // 线程开始运行
class MyRunnabble implements Runnable{

    @Override
    public void run() {
        while (true)
        {
            System.out.println("123__true");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class test1 {
    public static void main(String[] args) {
        MyRunnabble runnabble=new MyRunnabble();
        Thread t=new Thread(runnabble);
        t.start();
        while (true) {
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}
  1. 继承 Thread 类, 直接使用 this 就表示当前线程对象的引用.
  2. 实现 Runnable 接口, this 表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()

常见方法:

方法 说明
Thread() 创建线程对象
Thread(Runnable target) 使用 Runnable 对象创建线程对象
Thread(String name) 创建线程对象,并命名
Thread(Runnable target, String name) 使用 Runnable 对象创建线程对象,并命名

常见属性:

Java多线程(一)多线程概要,linux,java,服务器

// 使用匿名类创建 Thread 子类对象

Thread t1 = new Thread() {

   @Override

   public void run() {

       System.out.println("使用匿名类创建 Thread 子类对象");

  }

};

// 使用匿名类创建 Runnable 子类对象

Thread t2 = new Thread(new Runnable() {

   @Override

   public void run() {

       System.out.println("使用匿名类创建 Runnable 子类对象");

  }

});

// 使用 lambda 表达式创建 Runnable 子类对象

Thread t4 = new Thread(() -> {

   System.out.println("使用匿名类创建 Thread 子类对象");

});

多线程的优势

1. 增加运行速度,通过记录时间戳

        使用 System.nanoTime() 可以记录当前系统的纳秒级时间戳.

        

public class test3 {
     static int count=0;
    public synchronized static void sum(){
        count++;
    }
    public static void main(String[] args) throws InterruptedException {
        long time=System.currentTimeMillis();
        Thread t1=new Thread(()->{
                for (int i = 0; i < 10000; i++) {
                    sum();
                }
        });
        Thread t2=new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                sum();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
        System.out.println(System.currentTimeMillis()-time);
    }
}
  1. ID 是线程的唯一标识,不同线程不会重复
  2. 名称是各种调试工具用到
  3. 状态表示线程当前所处的一个情况,下面我们会进一步说明
  4. 优先级高的线程理论上来说更容易被调度到
  5. 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  6. 是否存活,即简单的理解,为 run 方法是否运行结束了
  7. 线程的中断问题,下面我们进一步说明
中断问题:

一个程序要执行很多次,可是我们突然有了一个需求要添加,就得让这个程序停下来,所以我就需要线程中断。

目前常见的有以下两种方式:

1. 通过共享的标记来进行沟通

注意变量捕获,但是java中要求变量捕获,捕获的变量的必须要final或者“实际final”及没有用final修饰,但是代码中没有做出修改。

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        public volatile boolean isQuit = false;
        @Override
        public void run() {
            while (!isQuit) {
                System.out.println(Thread.currentThread().getName()
                        + ": 转账");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
           }
           
       }
   }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 通知李四对方是个骗子!");
        target.isQuit = true;
   }
}
2. 调用 interrupt() 方法来通知

使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定

义标志位.

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 两种方法均可以
            while (!Thread.interrupted()) {
            //while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + ": 转账!");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
       
                    break;
               }
           }

       }
   }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 开始转账。");
        thread.start();
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()
                + ": 对方是个骗子!");
        thread.interrupt();
   }
}
方法 说明
public void interrupt()

中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位

public static boolean

interrupted()

判断当前线程的中断标志位是否设置,调用后清除标志位

public boolean

isInterrupted()

判断对象关联的线程的标志位是否设置,调用后不清除标志位

thread 收到通知的方式有两种(这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到):

1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通

知,清除中断标志

  • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程.

2. 否则,只是内部的一个中断标志被设置,thread 可以通过

  • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
  • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

注意:interrupt():作用设置标志位true,如果该线程在阻塞中,此时会把阻塞状态唤醒,抛出异常的方式中断。(当sleep(也可看做阻塞)被唤醒会自动把interrupted,将标志位清空)

产生阻塞的方法,会使得看到标识位为true,任然会抛出异常和清空标志,如果设置interrupt的时候,阻塞巧合醒了,这个时候程序执行到下一个循环判断条件就结束了。

等待一个线程-join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。这样可以让线程变得可控。线程的调度是随机的,无法判定两个线程谁先结束,谁先开始。而jion就是确定谁先开始的方法。

方法 说明
public void join() 等待线程结束
public void join(long millis) 等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos) 同理,但可以更高精度
public class test2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(){
            @Override
            public void run() {
                while (true) {

                    System.out.println("123545_run");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                    }
                }
            }
        };
        t.start();
        t.join();
        while (true) {

            System.out.println("123545_run");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

NEW: 安排了工作, 还未开始行动

RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.

BLOCKED: 这几个都表示排队等着其他事情

WAITING: 这几个都表示排队等着其他事情

TIMED_WAITING: 这几个都表示排队等着其他事情

TERMINATED: 工作完成了.

public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
       }
   }
}

Java多线程(一)多线程概要,linux,java,服务器

BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.

TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒文章来源地址https://www.toymoban.com/news/detail-701974.html

到了这里,关于Java多线程(一)多线程概要的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 十年JAVA搬砖路——Linux搭建Ldap服务器。

    1.安装命令 2.启动ldap 3.修改密码 获得返回的密码加密密码串: {SSHA}DkSw0+43+u4PK7c7F1GtoubEWHnrz3bG 去slapd.d 目录 创建db.ldif 文件 文件内容: #各个命令的说明 { 第一条语句修改了olcSuffix属性,该属性表示LDAP目录的后缀(基础DN)。它被替换为\\\"dc=ricman,dc=localhost\\\"。 第二条语句修改了

    2024年02月06日
    浏览(38)
  • java根据服务器(linux)端ip+文件路径将服务器端文件下载到本地

    jsch:Maven Repository: com.jcraft » jsch » 0.1.55 (mvnrepository.com)​​​​​  

    2024年02月11日
    浏览(66)
  • Java中将本服务器的文件拷贝到另一个服务器(Windows to Linux)

    在Java中,将文件从Windows服务器复制到Linux服务器,常用的方式是使用SSH进行安全的文件传输。Java有一个名为 JSch 的库,可以用于SSH连接和操作。 首先,你需要将 JSch 添加到你的项目依赖中。如果你使用的是Maven,你可以添加以下依赖: 然后,你可以使用以下代码将文件从

    2024年02月11日
    浏览(49)
  • [linux实战] 华为云耀云服务器L实例 Java、node环境配置

    本文介绍了在华为云耀云服务器L实例上配置Java和Node环境的步骤,包括修改密码、配置安全规则、远程登录、安装JDK、安装Git、安装Maven以及安装Node和Npm。 关键词:华为云耀云服务器L实例,Java环境配置,Node环境配置,安装JDK,安装Git,安装Maven,安装Node,安装Npm

    2024年02月10日
    浏览(218)
  • Java利用JSCH库远程连接Linux服务器以及操作多条Shell命令

    为了实现 DHCP 服务器的 IP 存储、回收和查询机制,我们需要将服务器中 LXD 容器的网卡 IP 查询出来,并且存储到服务器中的 Mysql 中。所以,下面介绍如何通过 Java 远程连接 Linux 服务器以及操作多条 Shell 命令。 创建 Maven 项目,导入依赖 jsch 实现远程连接,往后我们只需要调

    2024年02月13日
    浏览(51)
  • 【Linux网络编程】高并发服务器框架 线程池介绍+线程池封装

    前言 一、线程池介绍 💻线程池基本概念 💻线程池组成部分 💻线程池工作原理  二、线程池代码封装 🌈main.cpp 🌈ThreadPool.h 🌈ThreadPool.cpp 🌈ChildTask.h  🌈ChildTask.cpp 🌈BaseTask.h 🌈BaseTask.cpp 三、测试效果 四、总结 📌创建线程池的好处 本文主要学习 Linux内核编程 ,结合

    2024年01月16日
    浏览(95)
  • 【Linux后端服务器开发】封装线程池实现TCP多线程通信

    目录 一、线程池模块 Thread.h LockGuard.h ThreadPool.h 二、任务模块模块 Task.h 三、日志模块 Log.h 四、守护进程模块 Deamon.h  五、TCP通信模块 Server.h Client.h server.cpp client.cpp 关于TCP通信协议的封装,此篇博客有详述: 【Linux后端服务器开发】TCP通信设计_命运on-9的博客-CSDN博客 线程池

    2024年02月16日
    浏览(45)
  • Linux网络编程:多进程 多线程_并发服务器

    文章目录: 一:wrap常用函数封装 wrap.h  wrap.c server.c封装实现 client.c封装实现 二:多进程process并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 三:多线程thread并发服务器 server.c服务器 实现思路 代码逻辑  client.c客户端 ​​​​   read 函数的返回值 wrap.h  wrap

    2024年02月12日
    浏览(56)
  • Linux网络编程:线程池并发服务器 _UDP客户端和服务器_本地和网络套接字

    文章目录: 一:线程池模块分析 threadpool.c 二:UDP通信 1.TCP通信和UDP通信各自的优缺点 2.UDP实现的C/S模型 server.c client.c 三:套接字  1.本地套接字 2.本地套 和 网络套对比 server.c client.c threadpool.c   server.c client.c server.c client.c

    2024年02月11日
    浏览(66)
  • 【Minecraft】10分钟教你搭建我的世界Java版开服教程【Linux服务器+MCSManager管理面板】

     一个人玩游戏没啥意思,和朋友一块联机呢,距离太远,家庭局域网宽带又没有公网ip,你的朋友没办法与你联机,然而你只需要一台服务器即可搞定了;但是很多用户没没接触过相关的内容,具体的该怎么操作呢?下面我将吧详细的教程分享给大家,适合完全零基础,跟着

    2024年02月09日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包