请选择 进入手机版 | 继续访问电脑版

三郎之——Java【多线程】

[复制链接]

三郎之——Java【多线程】

发表于 2022-1-12 14:18:22 只看大图 阅读模式 正序浏览
1576 0 查看全部

  1. 大家好划水的三郎更新多线程了多多指点欢迎大家留言讨论
复制代码
目录
线程概述
        进程介绍
        线程介绍
创建线程的三种方式
        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方法。

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

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

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

  17.         for (int i = 0; i ‹ 5; i++) {
  18.             System.out.println("三郎学习多线程"+(i+1));
  19.         }
  20.     }
  21. }
复制代码

  运行结果如下线程由CPU调度每次执行结果都会不同不必多疑。
  1. 三郎学习多线程1
  2. 文章对您有用的话点赞关注支持一下1
  3. 文章对您有用的话点赞关注支持一下2
  4. 文章对您有用的话点赞关注支持一下3
  5. 三郎学习多线程2
  6. 文章对您有用的话点赞关注支持一下4
  7. 三郎学习多线程3
  8. 文章对您有用的话点赞关注支持一下5
  9. 三郎学习多线程4
  10. 三郎学习多线程5
复制代码

总结线程调用start方法开启之后未必执行由CPU进行调度看CPU心情。
[/code] 2.实现Runnable接口  重点实现Runnable接口重写run方法run方法里面是线程体也就是新线程的入口调用start方法启动线程。启动方式new Thread(线程对象).start方法。

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

  3. //实现Runnable接口
  4. public class StudyCSDNRunnable implements Runnable{
  5.     //重写run方法
  6.     @Override
  7.     public void run() {
  8.         for (int i = 0; i ‹ 5; i++) {
  9.             System.out.println("文章对您有用的话点赞关注支持一下"+(i+1));
  10.         }
  11.     }
  12.     //主线程
  13.     public static void main(String[] args) {
  14.         //创建一个线程对象
  15.         StudyCSDNRunnable studyCSDNRunnable = new StudyCSDNRunnable();
  16.         //只有Thread才有start方法,new Thread(),放入我们的线程对象。调用start方法
  17.         new Thread(studyCSDNRunnable).start();
  18.         for (int i = 0; i ‹ 5; i++) {
  19.             System.out.println("三郎学习多线程"+(i+1));
  20.         }
  21.     }
  22. }
复制代码

运行结果如下跟方式一 一样线程由CPU进行调度每次执行接口都可能不一样。
  1. 三郎学习多线程1
  2. 文章对您有用的话点赞关注支持一下1
  3. 三郎学习多线程2
  4. 文章对您有用的话点赞关注支持一下2
  5. 三郎学习多线程3
  6. 文章对您有用的话点赞关注支持一下3
  7. 三郎学习多线程4
  8. 文章对您有用的话点赞关注支持一下4
  9. 文章对您有用的话点赞关注支持一下5
  10. 三郎学习多线程5
复制代码

总结推荐使用Runnable可摆脱Java单继承的局限性。线程调用start方法开启之后未必执行由CPU进行调度看CPU心情。
[/code] 3.实现Callable接口  了解即可实现callable接口,需要返回值给一个返回值类型String,不写默认Object重写call方法会抛出一个异常 throws Exception。

  1.   测试过程创建StudyCSDNCallable类实现Callable接口重写call方法创建主线程main主函数执行程序创建线程池执行线程获取运行结果关闭线程池。
  2. [code]package com.example.demo.test;

  3. import java.util.concurrent.*;

  4. //实现callable接口,需要返回值给一个返回值类型String,不写默认Object
  5. public class StudyCSDNCallable implements Callable‹String> {
  6.     private String name;
  7.     private String study;
  8.     //构造方法
  9.     public StudyCSDNCallable(String name, String study) {
  10.         this.name = name;
  11.         this.study = study;
  12.     }
  13.     //重写call方法会抛出一个异常 throws Exception
  14.     @Override
  15.     public String call() throws Exception {
  16.         //输出可以看到是多线程执行
  17.         System.out.println(study);
  18.         //返回值
  19.         return name+study;
  20.     }
  21.     //主线程
  22.     public static void main(String[] args) throws ExecutionException,InterruptedException {
  23.         //传入两个参数看是否是多线程执行
  24.         StudyCSDNCallable studyCSDNCallable1 = new StudyCSDNCallable("三郎===","3.1学习多线程");
  25.         StudyCSDNCallable studyCSDNCallable2 = new StudyCSDNCallable("三郎===","3.2实现callable");
  26.         //创建一个线程池放入两个线程线程池重点内容后续单独出一篇文章解释
  27.         ExecutorService executorService = Executors.newFixedThreadPool(2);
  28.         //执行线程
  29.         Future‹String> submit1 = executorService.submit(studyCSDNCallable1);
  30.         Future‹String> submit2 = executorService.submit(studyCSDNCallable2);
  31.         //运行结果
  32.         String zyj1 = submit1.get();
  33.         //打印运行结果
  34.         System.out.println(zyj1);
  35.         String zyj2 = submit2.get();
  36.         //打印运行结果
  37.         System.out.println(zyj2);
  38.         //关闭线程池
  39.         executorService.shutdown();

  40.     }
  41. }
复制代码

运行结果线程由CPU进行调度每次执行接口都可能不一样。文中使用的线程数少可以多试几次或者多来几个线程。
  1. 3.2实现callable
  2. 3.1学习多线程
  3. 三郎===3.1学习多线程
  4. 三郎===3.2实现callable
复制代码

总结非重点此了解即可。
[/code] 线程的六种状态

  1. 很多博客上都是五种状态但其实是六种初始状态运行状态也称就绪状态阻塞状态等待状态等待状态分为两种等待指定时间状态和等待状态还有终止状态。摘自翻译的Java中文官方文档文档在文章最后可下载由下载链接。
  2.   
复制代码
线程执行状态流程图  图文详解
watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZCO56uv5LiJ6YOOQFpZSg==,size_20,color_FFFFFF,t_70,g_se,x_16.jpg
1.NEW  初始状态尚未启动的线程的线程状态。
2.RUNNABLE  运行状态就绪状态一个可运行的线程的线程状态。 由CPU决定CPU已经调度的话是运行状态就绪状态就是CPU还没有进行调度已经做好被调度的准备。
3.BLOCKED  阻塞状态线程阻塞等待监视器锁的线程状态。
4.WAITING  等待状态等待线程的线程状态。
5.TIMED_WAITING  等待指定时间状态具有指定等待时间的等待线程的线程状态。
6.TERMINATED  终止状态 终止线程的线程状态。 线程终止不可再次开启。
状态测试代码块

  1. [code]package com.example.demo.test;

  2. public class StudyCSDNState implements Runnable{

  3.     public synchronized static void main(String[] args) throws InterruptedException {
  4.         System.out.println("###---start---###");
  5.         System.out.println("===线程的创建-运行-终止===");
  6.         //创建线程对象
  7.         StudyCSDNState studyCSDNState = new StudyCSDNState();
  8.         //创建Thread方法
  9.         Thread thread = new Thread(studyCSDNState);
  10.         System.out.println("===没有调用start方法前当前线程的状态"+thread.getState());
  11.         //调用start方法
  12.         thread.start();
  13.         System.out.println("===调用start后线程状态"+thread.getState());
  14.         Thread.sleep(100);
  15.         System.out.println("===线程进入等待状态"+thread.getState());
  16.         Thread.sleep(2000);
  17.         System.out.println("===等待两秒查看线程状态"+thread.getState());
  18.         System.out.println("###---end---###");
  19.     }

  20.     @Override
  21.     public void run() {
  22.         try {
  23.             Thread.sleep(1000);
  24.         } catch (InterruptedException e) {
  25.             e.printStackTrace();
  26.         }
  27.     }
  28. }
复制代码

运行结果如下
  1. ###---start---###
  2. ===线程的创建-运行-终止===
  3. ===没有调用start方法前当前线程的状态NEW
  4. ===调用start后线程状态RUNNABLE
  5. ===线程进入等待状态TIMED_WAITING
  6. ===等待两秒查看线程状态TERMINATED
  7. ###---end---###
复制代码

[/code] 实现抢票功能  一共有10张车票创建了三个不同的对象来抢购。
多线程带来的问题

  1. 当多个线程操作同一对象的时候就会有抢错负数抢到同一张等的情况发生下面代码是抢错的代码可试验一下。
  2. [code]package com.example.demo.test;

  3. /**
  4. *多个线程操作同一个对象
  5. *买火车票为例子
  6. *
  7. * 发现问题多个线程操作同一个对象线程不安全了数据混乱
  8. *
  9. */
  10. public class StudyRunnable2 implements Runnable{

  11.     //10张车票
  12.     private Integer fare = 10;
  13.     private Boolean change = true;

  14.     @Override
  15.     public void run() {
  16.         while (change){
  17.             try {
  18.                 zyj();
  19.             } catch (InterruptedException e) {
  20.                 e.printStackTrace();
  21.             }
  22.         }
  23.     }

  24.     public void zyj() throws InterruptedException {
  25.             if(fare‹=0){
  26.                 change = false;
  27.                 return;
  28.             }
  29.             Thread.sleep(100);
  30.             System.out.println(Thread.currentThread().getName()+"----->拿到了第"+fare--+"票");
  31.     }

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

  39. }
复制代码

[/code] 解决方法

  1. 使用synchronized关键字修饰由于java的每个对象都有一个内置锁当用此关键字修饰方法时 内置锁会保护整个方法。在调用该方法前需要获得内置锁否则就处于阻塞状态。
  2. 修改上边的代码找到zyj()方法在此方法加上synchronized即可修改的代码如下
  3. [code]public synchronized void zyj() throws InterruptedException {
  4.             if(fare‹=0){
  5.                 change = false;
  6.                 return;
  7.             }
  8.             Thread.sleep(100);
  9.             System.out.println(Thread.currentThread().getName()+"----->拿到了第"+fare--+"票");
  10.     }
复制代码

运行结果运行出来若都是一个人拿到的话多运行几次这个CPU决定的。
  1. 张三----->拿到了第10票
  2. 张三----->拿到了第9票
  3. 张三----->拿到了第8票
  4. 张三----->拿到了第7票
  5. 张三----->拿到了第6票
  6. 张三----->拿到了第5票
  7. 张三----->拿到了第4票
  8. 李四----->拿到了第3票
  9. 李四----->拿到了第2票
  10. 王五----->拿到了第1票
复制代码

  总结使用synchronized会影响效率不使用会导致数据混乱在数据安全方面还是舍弃效率吧synchronized最好加在修改数据的方法上可以少影响点效率。
注:产品改需求了............此处省略一万字.........得写代码了线程池等后续单独出一篇。
[/code] Java中文文档  百度网盘链接https://pan.baidu.com/s/124_gXmqRs5Ng8LUW_Buq8A
提取码i6i8

来源:CSDN
回复

使用道具 举报

游客~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|极客同行 ( 蜀ICP备17009389号-1 )

© 2013-2016 Comsenz Inc. Powered by Discuz! X3.4