我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java 多线程之两步掌握

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java 多线程之两步掌握

导论:初识多线程

首先,我们来讨论讨论什么叫做多线程。举个简单的例子,比如说造房子这个任务。如果只有一个人的话,他既要搬砖还得拎砂浆、搅拌水泥之类的(其他工种这里就不一一阐述了),哪怕这个工人技术再熟练,精力再旺盛,他同时也只能干一个工种。那么问题来了,该如何提升效率呢?很简单,我们可以请多个工人同时来干活,可以同时干多种也可以干同种活儿,这样效率就高得多。尽管他们各自可干着不同的活儿,但本质都是为了造房子这个任务,这就叫做多进程,即将一个大任务拆分成不同的小任务,分配不同的人来执行,当包工头也就是处理器下达命令时,他们按照指令来工作。

每个工种的话,比如搅拌水泥的大工优惠叫来几个小工,都是来干搅拌水泥这个活儿,所以这里叫做多线程。

那么,怎么区分多进程和多线程呢?这里简单概括:

进程是系统分配资源的最小单位,线程是系统调度的最小单位。一个进程内的线程之间是可以共享资源的。 每个进程至少有一个线程存在,即主线程。

一:动手来创建多线程

1.1 创建一个主线程

请看代码:


public class ThreadDemo1 {
    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("hello world, 我是一个线程");
            while (true) {
 
            }
        }
    }
 
    public static void main(String[] args) {
        // 创建线程需要使用 Thread 类, 来创建一个 Thread 的实例.
        // 另一方面还需要给这个线程指定, 要执行哪些指令/代码.
        // 指定指令的方式有很多种方式, 此处先用一种简单的, 直接继承 Thread 类,
        // 重写 Thread 类中的 run 方法.
 
        // [注意!] 当 Thread 对象被创建出来的时候, 内核中并没有随之产生一个线程(PCB).
        Thread t = new MyThread();
        // 执行这个 start 方法, 才是真的创建出了一个线程.
        // 此时内核中才随之出现了一个 PCB, 这个 PCB 就会对应让 CPU 来执行该线程的代码. (上面的 run 方法中的逻辑)
        t.start();
 
        while (true) {
            // 这里啥都不干
        }
    }
}

接下里,我们可以通过jdk里面的一个jconsole来查看,我的文件路径是C:\Program Files\Java\jdk1.8.0_192\bin,大家可以对照自己安装的jdk文件位置来寻找。运行程序,打开jconsole可以看下

这里这个主线程就是我们创建的线程,线程创建成功。

1.2 多线程抢占式执行

创建两个线程,输出线程运行前后时间,多次运行发现运行时间不一,这里就体现了现成的抢占式执行方法,看代码:


public class ThreadDemo2 {
    private static long count = 100_0000_0000L;
 
    public static void main(String[] args) {
        // serial();
        concurrency();
    }
 
    private static void serial() {
        long beg = System.currentTimeMillis();
 
        int a = 0;
        for (long i = 0; i < count; i++) {
            a++;
        }
        int b = 0;
        for (long i = 0; i < count; i++) {
            b++;
        }
 
        long end = System.currentTimeMillis();
        System.out.println("time: " + (end - beg) + " ms");
    }
 
    private static void concurrency() {
        long beg = System.currentTimeMillis();
 
        Thread t1 = new Thread() {
            @Override
            public void run() {
                int a = 0;
                for (long i = 0; i < count; i++) {
                    a++;
                }
            }
        };
 
        Thread t2 = new Thread() {
            @Override
            public void run() {
                int b = 0;
                for (long i = 0; i < count; i++) {
                    b++;
                }
            }
        };
        t1.start();
        t2.start();
 
        try {
            // 线程等待. 让主线程等待 t1 和 t2 执行结束, 然后再继续往下执行.
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        // t1 t2 和 main 线程之间都是并发执行的.
        // 调用了 t1.start 和 t2.start 之后, 两个新线程正在紧锣密鼓的进行计算过程中,
        // 此时主线程仍然会继续执行, 下面的 end 就随之被计算了.
        // 正确的做法应该是要保证 t1 和 t2 都计算完毕, 再来计算这个 end 的时间戳.
        long end = System.currentTimeMillis();
        System.out.println("time: " + (end - beg) + " ms");
    }
}

多次运行,会有以下结果:

可以发现线程是抢占式执行。

我们用join关键字,可以规定线程运行先后顺序,比如这里规定t1运行完后t2再运行,代码如下:


public class ThreadDemo2 {
    private static long count = 100_0000_0000L;
 
    public static void main(String[] args) {
         serial();
        //concurrency();
    }
 
    private static void serial() {
        long beg = System.currentTimeMillis();
 
        int a = 0;
        for (long i = 0; i < count; i++) {
            a++;
        }
        int b = 0;
        for (long i = 0; i < count; i++) {
            b++;
        }
 
        long end = System.currentTimeMillis();
        System.out.println("time: " + (end - beg) + " ms");
    }
 
    private static void concurrency() {
        long beg = System.currentTimeMillis();
 
        Thread t1 = new Thread() {
            @Override
            public void run() {
                int a = 0;
                for (long i = 0; i < count; i++) {
                    a++;
                }
            }
        };
 
        Thread t2 = new Thread() {
            @Override
            public void run() {
                int b = 0;
                for (long i = 0; i < count; i++) {
                    b++;
                }
            }
        };
        t1.start();
        t2.start();
 
        try {
            // 线程等待. 让主线程等待 t1 和 t2 执行结束, 然后再继续往下执行.
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
 
        // t1 t2 和 main 线程之间都是并发执行的.
        // 调用了 t1.start 和 t2.start 之后, 两个新线程正在紧锣密鼓的进行计算过程中,
        // 此时主线程仍然会继续执行, 下面的 end 就随之被计算了.
        // 正确的做法应该是要保证 t1 和 t2 都计算完毕, 再来计算这个 end 的时间戳.
        long end = System.currentTimeMillis();
        System.out.println("time: " + (end - beg) + " ms");
    }
}

多次运行,结果如下:

这里发现,由于规定了线程运行先后时间,导致运行时间大大增长,由此体现了线程并发运行的优势所在。

这里说明一点:由于线程是抢占式执行,所以每次结果都是不一定的,但误差会在一定范围内。

二:创建线程的几个常用方法

2.2 继承 Thread 类

可以通过继承 Thread 来创建一个线程类,该方法的好处是 this 代表的就是当前线程,不需要通过 Thread.currentThread() 来获取当前线程的引用。

class MyThread extends Thread {

@Override

public void run ()

{ System . out . println ( " 这里是线程运行的代码 " );

}

}

MyThread t = new MyThread ();

t . start (); // 线程开始运行

2.2 实现 Runnable 接口

通过实现 Runnable 接口,并且调用 Thread 的构造方法时将 Runnable 对象作为 target 参数传入来创建线程对象。 该方法的好处是可以规避类的单继承的限制;但需要通过 Thread.currentThread() 来获取当前线程的引用。

class MyRunnable implements Runnable {

@Override

public void run () {

System . out . println ( Thread . currentThread (). getName () + " 这里是线程运行的代码 " );

}

}

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

t.start(); // 线程开始运行

2.3 匿名类创建

// 使用匿名类创建 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 t3 = new Thread(() -> System.out.println(" 使用匿名类创建 Thread 子类对象 "));

Thread t4 = new Thread(() -> {

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

});

三:Thread的几个常见属性

代码如下:


public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    System.out.println(Thread.currentThread().getName() + ": 我还活着");
                    Thread.sleep(1 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ": 我即将死去");
        });
        thread.start();
        System.out.println(Thread.currentThread().getName()
                + ": ID: " + thread.getId());
        System.out.println(Thread.currentThread().getName()
                + ": 名称: " + thread.getName());
        System.out.println(Thread.currentThread().getName()
                + ": 状态: " + thread.getState());
        System.out.println(Thread.currentThread().getName()
                + ": 优先级: " + thread.getPriority());
        System.out.println(Thread.currentThread().getName()
                + ": 后台线程: " + thread.isDaemon());
        System.out.println(Thread.currentThread().getName()
                + ": 活着: " + thread.isAlive());
        System.out.println(Thread.currentThread().getName()
                + ": 被中断: " + thread.isInterrupted());
 
        while (thread.isAlive()) {}
        System.out.println(Thread.currentThread().getName()
                + ": 状态: " + thread.getState());
    }
}

运行结果:

由此可见各个关键字的含义,今天的分享就到这里。

记:

最近刚开学,各种事儿,选导师,研一七天都有课,导致时间紧张,希望自己还是可以平衡好学业和代码的关系吧,谢谢大家支持。

整理不易,大家多多支持。

到此这篇关于Java 多线程之两步掌握的文章就介绍到这了,更多相关Java 多线程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java 多线程之两步掌握

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

【Java】你掌握了多线程吗?

【文末送书】今天推荐一本Java多线程编程领域新书《一本书讲透Java线程》 摘要 互联网的每一个角落,无论是大型电商平台的秒杀活动,社交平台的实时消息推送,还是在线视频平台的流量洪峰,背后都离不开多线程技术的支持。在数字化转型的过程中
【Java】你掌握了多线程吗?
2023-12-22

如何掌握 Java Desktop 多线程编程技巧?(java desktop多线程编程技巧)

在Java编程中,多线程编程是一个重要的概念和技能。它允许程序同时执行多个任务,提高程序的性能和响应性。对于JavaDesktop应用程序来说,多线程编程更是必不可少的,因为它可以让用户界面更加流畅,同时处理后台任务。本文将介绍JavaDesktop多线程编程的技巧,帮助你更好
如何掌握 Java Desktop 多线程编程技巧?(java desktop多线程编程技巧)
Java2024-12-19

Java多线程程序如何掌握基本语法

本篇文章为大家展示了Java多线程程序如何掌握基本语法,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java多线程程序需要我们具体的学习相关语法。其中我们要了解相关的语法究竟有什么。很多重要的问题成
2023-06-17

java多线程之线程同步的方法有哪些

Java中线程同步的方法有以下几种:1. synchronized关键字:使用synchronized关键字可以实现对代码块、方法或对象的同步,确保同一时间只有一个线程可以访问被同步的代码块、方法或对象。2. ReentrantLock类:
2023-09-27

Java 多线程编程:你是否掌握了这些基本要点?

在这篇博客中,我将深入探讨Java中的Thread、Thread.sleep()、线程优先级、守护线程、UncaughtExceptionHandler等内容。

Python编程进阶,轻松掌握多线程和多进程

多线程是在单个进程中实现并行性的一种方法,能够执行同时进行的任务。在单个进程内可以创建多个线程,并在该进程内并行执行较小的任务。

Java线程同步与互斥:多线程编程的必备技能,掌握它,让你的程序如丝般顺滑

多线程编程是一项复杂的技能,需要对线程同步和互斥有深入的理解。本文将介绍Java中的线程同步和互斥,并提供示例代码,帮助您掌握多线程编程的必备技能,让您的程序运行顺畅如丝。
Java线程同步与互斥:多线程编程的必备技能,掌握它,让你的程序如丝般顺滑
2024-02-09

掌握这五种多线程方法,提高Java代码效率

适当地使用这些下面这些方法,可以彻底改变您的应用程序,并推动您的职业发展。下面我们来看看如何将您的应用程序转变为高效的多线程应用。

Java多线程之线程状态

关于Java线程的状态,有的人可能会说有4种状态,有的会说有5种,6种,总之各种各样的说法可能都有。造成这种情况的原因是:有很多的书上常常把操作系统进程状态,线程状态与Java线程状态混在一起谈。

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录