java之多线程

java之多线程简介:线程(thread)就是进程中的一个执行线索。Java虚拟机允许进程中同时执行多个线程。每个线程都有一个优先级。具有较高优先级的线程先执行。线程是操作系统分配CPU时间的基本实体。每一个

大家好,又见面了,我是你们的朋友全栈君。

简介

  线程(thread)就是进程中的一个执行线索。Java虚拟机允许进程中同时执行多个线程。每个线程都有一个优先级。具有较高优先级的线程先执行。
  线程是操作系统分配 CPU 时间的基本实体。每一个应用程序至少有一个线程,也可以拥有多个线程。线程是程序中的代码流。多个线程可以同时运行并能共享资源。
  线程与进程不同,每个进程都需要操作系统为其分配独立的地址空间,而同一进程中的各个线程是在同一块地址空间中工作。

线程存在一个生命周期,由以下方法体现

  (1)  start()方法:启动一个线程。
  (2)  run()方法:定义该线程的动作。
  (3)  sleep()方法:使线程睡眠一段时间,单位为ms。
  (4)  suspend()方法:使线程挂起。
  (5)  resume()方法:恢复挂起的线程。
  (6)  yield()方法:把线程移到队列的尾部。
  (7)  stop()方法:结束线程生命周期并执行清理工作。
  (8)  destroy()方法:结束线程生命周期但不做清理工作。
       其中最常用的是方法start()、run()、sleep()、stop()。

线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、销毁。

  • 新建:就是刚使用new方法,new出来的线程;

  • 就绪:就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;

  • 运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;

  • 阻塞:在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如sleep()、wait()之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用notify或者notifyAll()方法。唤醒的线程不会立刻执行run方法,它们要再次等待CPU分配资源进入运行状态;

  • 销毁:如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源;

JAVA 线程实现/创建方式

1、继承 Thread 类

  Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方 法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,它将启动一个新线 程,并执行 run()方法。

1 public class MyThread extends Thread { 2     public void run() { 3         System.out.println("MyThread.run()"); 4  } 5 } 6 
7 MyThread myThread1 = new MyThread(); 8 myThread1.start();    

2、实现 Runnable 接口

  如果自己的类已经 extends 另一个类,就无法直接 extends Thread,此时,可以实现一个 Runnable 接口。

 1 public class MyThread extends OtherClass implements Runnable {  2     public void run() {  3         System.out.println("MyThread.run()");  4  }  5 }  6 
 7 //启动 MyThread,需要首先实例化一个 Thread,并传入自己的 MyThread 实例:
 8 MyThread myThread = new MyThread();  9 Thread thread = new Thread(myThread); 10 thread.start(); 11 
12 //事实上,传入一个 Runnable target 参数给 Thread 后,Thread 的 run()方法就会调用target.run()
13 public void run() { 
14   if (target != null) {
15     target.run();
16   }  

17 }  

3、通过Callable和Future创建有返回值线程

  有返回值的任务必须实现 Callable 接口,类似的,无返回值的任务必须 Runnable 接口。执行 Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务 返回的 Object 了。

 1 /*
 2  * 首先说一下步骤:
 3  * 1.创建Callable接口的实现类,并实现call()方法,该call()方法将作为
 4  *         线程执行体,并且有返回值。
 5  * 2.创建Callable实现类的实例,使用FutureTask类来包装Callable对象,
 6  *      该FutureTask对象封装了Callable对象的call()方法的返回值。
 7  * 3.使用FutureTask对象作为Thread对象的target创建并启动新线程。
 8  * 4.调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
 9  */
10 class MyCallable implements Callable<Integer> {
11 
12     @Override
13     public Integer call() throws Exception {
14         // 线程需要完成的任务
15         return new Random().nextInt(100);
16     }
17 }
18 
19 public static void main(String[] args) {
20     MyCallable myCallable = new MyCallable();
21     FutureTask<Integer> futureTask = new FutureTask<>(MyCallable);
22     new Thread(futureTask).start();
23     // 可能做一些其他操作
24     try {
25         System.out.println("子线程的返回值:" + futureTask.get());
26     } catch (Exception e) {
27         System.out.println(e.getMessage());
28     }
29 }

4、基于线程池的方式

上面三种方式的案例都是通过 new Thread 进行创建的,其弊端如下:

  • 每次new Thread新建对象性能差。
  • 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机。
  • 缺乏更多功能,如定时执行、定期执行、线程中断。

线程资源是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池。其优势如下:

  • 重用存在的线程,减少对象创建、消亡的开销,性能佳。
  • 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
  • 提供定时执行、定期执行、单线程、并发数控制等功能

线程池结合Runnable接口,如下

 1 // 创建线程池
 2 ExecutorService threadPool = Executors.newFixedThreadPool(10);
 3 while(true) {
 4     threadPool.execute(new Runnable() { // 提交多个线程任务,并执行
 5         @Override
 6         public void run() {
 7             System.out.println(Thread.currentThread().getName() + " is running ..");
 8             try {
 9                 Thread.sleep(3000);
10             } catch (InterruptedException e) {
11                 e.printStackTrace();
12             }
13         }
14     });
15 }

线程池结合Callable接口,如下:

 1 //创建一个线程池
 2 ExecutorService pool = Executors.newFixedThreadPool(taskSize);
 3 // 创建多个有返回值的任务
 4 List<Future> list = new ArrayList<Future>(); 
 5 for (int i = 0; i < taskSize; i++) { 
 6     Callable c = new MyCallable(i + " "); 
 7     // 执行任务并获取 Future 对象
 8     Future f = pool.submit(c); 
 9     list.add(f); 
10 } 
11 // 关闭线程池
12 pool.shutdown(); 
13 // 获取所有并发任务的运行结果
14 for (Future f : list) { 
15     // 从 Future 对象上获取任务的返回值,并输出到控制台
16     System.out.println("res:" + f.get().toString()); 
17 } 

 

关于使用线程池管理线程,可单列一篇,详情可参考:

https://www.cnblogs.com/ymzsb/p/14881753.html

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/154771.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 微信模拟地理位置_微信伪装地理位置是什么个原理「建议收藏」

    微信模拟地理位置_微信伪装地理位置是什么个原理「建议收藏」展开全部微信的定位数据来源主要有,基站定位、GPS定位。原理主体为:通过劫持代码关闭636f70793231313335323631343130323136353331333366306537从基站获取位置程序运行,伪造CELLID伪造WIFIMAC地址通过Xposed模块进行模拟地理位置、基站信息并上传伪装信息到微信客户端进行系统欺骗进而达到伪装地理位置的目的。扩展资料:微信定位功能实践上…

  • vimrc配置[通俗易懂]

    vimrc配置[通俗易懂]插件管理gitclonehttps://github.com/VundleVim/Vundle.vim.git~/.vim/bundle/Vundle.vim主题monokaihttps://github.com/sickill/vim-monokaivimrcbashrctmuxzsh/oh-my-zshz

  • Android浏览器插件开发[通俗易懂]

    Android浏览器插件开发[通俗易懂]最近做android浏览器插件学到一些东西和大家分享:需要了解的有以下几个方面的知识:1.插件是什么2.android浏览器怎样加载插件和创建实例3浏览器插件和脚本语言的交互4插件内部的数据流一浏览器插件介绍:  1.1概述浏览插件本质是一个功能模块,是浏览器功能的一种扩充。其载体是dll或则so文件。它依附浏览器完成某一特定的功能。插件需要实现浏览器规定的一些函数这些函数叫着NPAPI.正是插件实现了这些函数才可以和浏览器交互。同时浏览器也为插件提供一些函数。在android平台下还有一些专有的函数

  • dirsearch使用方法_search函数的使用

    dirsearch使用方法_search函数的使用一、安装:Kali下:gitclonehttps://github.com/maurosoria/dirsearchcddirsearch/Windows下:GitHub的下载地址为:https://github.com/maurosoria/dirsearch其中,db文件夹为自带字典文件夹;reports为扫描日志文件夹;dirsearch.py为主程序文件(注:dirsearch程序必须使用python3以上才能运行);安装完成后将目录地址改为主程序解压地址,使用管理员

  • 一些常用单位之间的换算

    一些常用单位之间的换算一些常用单位之间的换算单位表格汇总单位表格汇总请注意下方的表格:目前只对链接(也就是文字颜色有变换的那个)产生了单位的换算,其他的没有做换算,如果有清楚的可以在本篇博文下留言,正确的留言单位换算就打算加上链接,错误的就请大家帮忙纠正一下,感谢各位配合!!!常用物理量的名称、符号和单位名称…

  • 动态规划之01背包问题及其优化(python实现)「建议收藏」

    动态规划之01背包问题及其优化(python实现)「建议收藏」动态规划之01背包问题及其优化(python实现)**背包问题(**Knapsackproblem)是一种组合优化的NP完全问题。问题描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。问题的名称来源于如何选择最合适的物品放置于给定背包中。解决思路:动态规划,对每一件物品遍历背包容量,当背包可容纳值大于等于当前物品,与之前已放…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号