IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 三郎之——Java【多线程】 -> 正文阅读

[Java知识库]三郎之——Java【多线程】

大家好,划水的三郎更新多线程了,多多指点,欢迎大家留言讨论

目录

线程概述

????????进程介绍

????????线程介绍

创建线程的三种方式

????????1.继承Thread

????????2.实现Runnable接口

????????3.实现Callable接口

线程的六种状态

????????线程执行状态流程图

????????1.NEW

????????2.RUNNABLE

????????3.BLOCKED

????????4.WAITING

????????5.TIMED_WAITING

????????6.TERMINATED

????????状态测试代码块

实现抢票功能

????????多线程带来的问题

????????解决方法

Java中文文档


线程概述

? ? ? ? 在跑步的过程之中做了些什么事情?看进程介绍和线程介绍理解多线程。

进程介绍

? ? ? ? ?进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。比如:美女去跑步了这一件事的整个过程。

线程介绍

? ? ? ? ?线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程中可以并发多个线程,每条线程并行执行不同的任务。比如:我们在跑步这个过程中同时做的事情,例如呼吸,听歌,摆POSS等等,这就是多线程。

创建线程的三种方式

1.继承Thread

? ? ? ? 重点:继承Thread类,重写run方法,run方法里面是线程体,也就是新线程的入口,调用start方法启动线程。启动方式:线程对象.start方法。

测试过程:创建StudyCSDNThread类,继承Thread类,重写run方法,创建主线程main主函数执行程序,run方法里面是一个for循环,调用start方法之后启动线程,由CPU就行调度,不归我们管了,让CPU自己去分配运行。

package com.example.demo.test;

//继承Thread类
public class StudyCSDNThread extends Thread{
    //重写run方法,新线程的入口
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("文章对您有用的话,点赞关注支持一下"+(i+1));
        }
    }

    public static void main(String[] args) {
        //创建一个线程对象
        StudyCSDNThread studyCSDNThread = new StudyCSDNThread();
        //调用start方法开启线程
        studyCSDNThread.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("三郎学习多线程"+(i+1));
        }
    }
}

?运行结果如下:线程由CPU调度,每次执行结果都会不同,不必多疑。

三郎学习多线程1
文章对您有用的话,点赞关注支持一下1
文章对您有用的话,点赞关注支持一下2
文章对您有用的话,点赞关注支持一下3
三郎学习多线程2
文章对您有用的话,点赞关注支持一下4
三郎学习多线程3
文章对您有用的话,点赞关注支持一下5
三郎学习多线程4
三郎学习多线程5

总结:线程调用start方法开启之后未必执行,由CPU进行调度,看CPU心情。

2.实现Runnable接口

? ? ? ? 重点:实现Runnable接口,重写run方法,run方法里面是线程体,也就是新线程的入口,调用start方法启动线程。启动方式:new Thread(线程对象).start方法。

测试过程:创建StudyCSDNRunnable类,实现Runnable接口,重写run方法,创建主线程main主函数执行程序,run方法里面是一个for循环,只有Thread类有start方法,通过new Thread调用start方法之后启动线程,由CPU就行调度,不归我们管了,让CPU自己去分配运行。

package com.example.demo.test;

//实现Runnable接口
public class StudyCSDNRunnable implements Runnable{
    //重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("文章对您有用的话,点赞关注支持一下"+(i+1));
        }
    }
    //主线程
    public static void main(String[] args) {
        //创建一个线程对象
        StudyCSDNRunnable studyCSDNRunnable = new StudyCSDNRunnable();
        //只有Thread才有start方法,new Thread(),放入我们的线程对象。调用start方法
        new Thread(studyCSDNRunnable).start();
        for (int i = 0; i < 5; i++) {
            System.out.println("三郎学习多线程"+(i+1));
        }
    }
}

运行结果如下:跟方式一 一样,线程由CPU进行调度,每次执行接口都可能不一样。

三郎学习多线程1
文章对您有用的话,点赞关注支持一下1
三郎学习多线程2
文章对您有用的话,点赞关注支持一下2
三郎学习多线程3
文章对您有用的话,点赞关注支持一下3
三郎学习多线程4
文章对您有用的话,点赞关注支持一下4
文章对您有用的话,点赞关注支持一下5
三郎学习多线程5

总结:推荐使用Runnable,可摆脱Java单继承的局限性。线程调用start方法开启之后未必执行,由CPU进行调度,看CPU心情。

3.实现Callable接口

? ? ? ? 了解即可:实现callable接口,需要返回值,给一个返回值类型String,不写默认Object,重写call方法,会抛出一个异常 throws Exception。

?测试过程:创建StudyCSDNCallable类,实现Callable接口,重写call方法,创建主线程main主函数执行程序,创建线程池,执行线程,获取运行结果,关闭线程池。

package com.example.demo.test;

import java.util.concurrent.*;

//实现callable接口,需要返回值,给一个返回值类型String,不写默认Object
public class StudyCSDNCallable implements Callable<String> {
    private String name;
    private String study;
    //构造方法
    public StudyCSDNCallable(String name, String study) {
        this.name = name;
        this.study = study;
    }
    //重写call方法,会抛出一个异常 throws Exception
    @Override
    public String call() throws Exception {
        //输出可以看到是多线程执行,
        System.out.println(study);
        //返回值
        return name+study;
    }
    //主线程
    public static void main(String[] args) throws ExecutionException,InterruptedException {
        //传入两个参数,看是否是多线程执行
        StudyCSDNCallable studyCSDNCallable1 = new StudyCSDNCallable("三郎===","3.1学习多线程");
        StudyCSDNCallable studyCSDNCallable2 = new StudyCSDNCallable("三郎===","3.2实现callable");
        //创建一个线程池,放入两个线程(线程池重点内容后续单独出一篇文章解释)
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //执行线程
        Future<String> submit1 = executorService.submit(studyCSDNCallable1);
        Future<String> submit2 = executorService.submit(studyCSDNCallable2);
        //运行结果
        String zyj1 = submit1.get();
        //打印运行结果
        System.out.println(zyj1);
        String zyj2 = submit2.get();
        //打印运行结果
        System.out.println(zyj2);
        //关闭线程池
        executorService.shutdown();

    }
}

运行结果:线程由CPU进行调度,每次执行接口都可能不一样。文中使用的线程数少,可以多试几次,或者多来几个线程。

3.2实现callable
3.1学习多线程
三郎===3.1学习多线程
三郎===3.2实现callable

总结:非重点,此了解即可。

线程的六种状态

很多博客上都是五种状态,但其实是六种,初始状态,运行状态,也称就绪状态,阻塞状态,等待状态,等待状态分为两种,等待指定时间状态和等待状态,还有终止状态。摘自翻译的Java中文官方文档,文档在文章最后可下载,由下载链接。

线程执行状态流程图

? ? ? ? 图文详解

1.NEW

? ? ? ? 初始状态:尚未启动的线程的线程状态。

2.RUNNABLE

? ? ? ? 运行状态(就绪状态):一个可运行的线程的线程状态。 由CPU决定,CPU已经调度的话是运行状态,就绪状态就是CPU还没有进行调度,已经做好被调度的准备。

3.BLOCKED

? ? ? ? 阻塞状态:线程阻塞等待监视器锁的线程状态。?

4.WAITING

? ? ? ? 等待状态:等待线程的线程状态。?

5.TIMED_WAITING

? ? ? ? 等待指定时间状态:具有指定等待时间的等待线程的线程状态。?

6.TERMINATED

? ? ? ?终止状态: 终止线程的线程状态。 线程终止不可再次开启。

状态测试代码块

package com.example.demo.test;

public class StudyCSDNState implements Runnable{

    public synchronized static void main(String[] args) throws InterruptedException {
        System.out.println("###---start---###");
        System.out.println("===线程的创建-运行-终止===");
        //创建线程对象
        StudyCSDNState studyCSDNState = new StudyCSDNState();
        //创建Thread方法
        Thread thread = new Thread(studyCSDNState);
        System.out.println("===没有调用start方法前,当前线程的状态"+thread.getState());
        //调用start方法
        thread.start();
        System.out.println("===调用start后线程状态"+thread.getState());
        Thread.sleep(100);
        System.out.println("===线程进入等待状态"+thread.getState());
        Thread.sleep(2000);
        System.out.println("===等待两秒,查看线程状态"+thread.getState());
        System.out.println("###---end---###");
    }

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下:

###---start---###
===线程的创建-运行-终止===
===没有调用start方法前,当前线程的状态NEW
===调用start后线程状态RUNNABLE
===线程进入等待状态TIMED_WAITING
===等待两秒,查看线程状态TERMINATED
###---end---###

实现抢票功能

????????一共有10张车票,创建了三个不同的对象来抢购。

多线程带来的问题

当多个线程操作同一对象的时候,就会有抢错,负数,抢到同一张等的情况发生,下面代码是抢错的代码,可试验一下。

package com.example.demo.test;

/**
 *多个线程操作同一个对象
 *买火车票为例子
 *
 * 发现问题:多个线程操作同一个对象线程不安全了,数据混乱
 *
 */
public class StudyRunnable2 implements Runnable{

    //10张车票
    private Integer fare = 10;
    private Boolean change = true;

    @Override
    public void run() {
        while (change){
            try {
                zyj();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void zyj() throws InterruptedException {
            if(fare<=0){
                change = false;
                return;
            }
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName()+"----->拿到了第"+fare--+"票");
    }

    public static void main(String[] args) {
        //单线程执行没有问题,多线程执行出现问题
        StudyRunnable2 studyRunnable2 = new StudyRunnable2();
        new Thread(studyRunnable2,"张三").start();
        new Thread(studyRunnable2,"李四").start();
        new Thread(studyRunnable2,"王五").start();
    }

}

解决方法

使用synchronized关键字修饰,由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,?内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。

修改上边的代码,找到zyj()方法,在此方法加上synchronized即可,修改的代码如下

public synchronized void zyj() throws InterruptedException {
            if(fare<=0){
                change = false;
                return;
            }
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName()+"----->拿到了第"+fare--+"票");
    }

运行结果:运行出来若都是一个人拿到的话,多运行几次,这个CPU决定的。

张三----->拿到了第10票
张三----->拿到了第9票
张三----->拿到了第8票
张三----->拿到了第7票
张三----->拿到了第6票
张三----->拿到了第5票
张三----->拿到了第4票
李四----->拿到了第3票
李四----->拿到了第2票
王五----->拿到了第1票

?总结:使用synchronized会影响效率,不使用会导致数据混乱,在数据安全方面,还是舍弃效率吧,synchronized最好加在修改数据的方法上,可以少影响点效率。

注:产品改需求了............此处省略一万字.........得写代码了,线程池等后续单独出一篇。

Java中文文档

百度网盘链接:https://pan.baidu.com/s/124_gXmqRs5Ng8LUW_Buq8A?
提取码:i6i8

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 01:50:01  更:2022-01-14 01:50:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:57:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码