申明:线程的概念以及进程的相关概念,可以参考网络上其他资料,这里只讨论多线程是怎么实现。

一、多线程的简单理解

明白什么是多线程,小生通俗一点的理解为:在一个程序里,我想同时让这个程序完成多个任务。

比如:让主函数 main 在打印1~100之间的所有整数的时候,要求在主函数打印到 20 的时候,再运行另一个类里的程序,让它打印10~100之间的所有整数。

这里忽略同进程内的多线程之间的抢占时间问题,上面的举例需求是要求一个程序只要有发生同时运行俩个程序的情况就行,即不准出现无论程序跑多少次都是先把 main 函数的1~100 的所有整数打印完再打印10~100 之间的所有整数(PS:如果是这样的话,那就是 main 调用其他类的方法,属于单线程了)。

二、创建多线程的三种方式(小生写的比较繁缀罗嗦,建议阅读完之后,参考代码再阅读一次。)

第一种方式:

创建:编写一个类 MyThread1 (这里只是小生的自定义命名,方便与代码里名称一致)让它继承 Thread 类,

并把需要多线程运行的程序放到 public void run() 方法里。

启动:在主函数中,new 出 MyThread1 类的实例。

运行:调用 MyThread1 类的实例的 start() 方法即可。

第二种方式:

创建:编写一个类 MyThread2 让它实现 Runnable 接口,并且要重写 run() 方法(把需要多线程运行的程序放到 public void run() 方法里)。

启动:在主函数中,new 出 MyThread1 类的实例,

new 出Thread 类(带有 target 的构造方法),

把MyThread1 类的实例作为参数传入Thread 类的构造方法里。

运行:调用 Thread 类的实例的 start() 方法即可。

第三种方式:

创建:实现 Callable 接口(小生定义这个类为 MyCallable),并且实现 call() 方法,注意 call() 方法是有返回值的。

启动:new 出Callable 接口的实现类MyCallable,

new 出 FutureTask 类的实例 task,

把call() 方法的返回值放入FutureTask 类的构造方法里,

把 task 放入 new 出的 Thread 构造方法里。

运行:调用 Thread 类的实例的 start() 方法即可。

三种方式的利弊总结:

  第一种方法好处:创建已经继承 Thread 类的类的实例,调用 start() 方法就能运行,代码写起来很方便,

    当然缺点就是继承了Thread 父类,就没有办法继承其他的类了,扩展性不好。所以一般不建议用这种方式创建多线程。

  第二种方法好处:继承接口,扩展性好。

    弊端是相对的,第一种方式不好也是相对于第二种来说的,而第二种方式相比第三种方式来说,run() 方法没有返回值,并且不能申明抛出异常。

  第三种方式好处上面已经说明,不好的就是编码很麻烦(小生太笨看了半天才搞明白)

四、创建多线程的三种方式的代码演示

说明:小生会对每种方式的每条线程进行重命名,只是为了方便代码运行效果演示。

java 默认线程的名称规则:java 中的 main 函数本身就是一个默认的主线程,名字为:main(在下面例子可以证实 main 线程在 jvm 中的默认名称)

如果自己定义的线程没有定义名称,则系统默认按照 Thread-0,Thread-1,……的命名方式进行命名。也可以通过对线程的构造方法进行重命名。

4.1 继承 Thread 类

  偷窥一下 API 发现 Thread 类实现了 Runnable 接口,currentThread() 静态方法返回当前线程这个实例,再 getName() 一下就得到当前线程的名字了。

   

  

  MyThread1 线程:

 package com.test.threadDemo1;

 public class MyThread1 extends Thread {

     public MyThread1(String name) {
this.setName(name);
} public void run() {
for(int i=20;i<=100;i++) {
System.out.println(getName()+"..."+i);
}
}
}

  main 线程:

 package com.test.threadDemo1;
/**
* 多线程的实现之一:继承 Thread 类
* @author Administrator
*
*/
public class ThreadDemo1 {
public static void main(String[] args) {
for (int i=1;i<=100;i++) {
System.out.println(Thread.currentThread().getName()+"..."+i); if(i==30) {
MyThread1 myThread = new MyThread1("新线程");
myThread.start();
}
}
}
}

  运行结果:(有交叉运行的情况发生,就是多线程了)

  从结果可以看出,当 main 线程跑到 30 的时候还在“抢占” CPU

  

4.2 实现 Runable 接口

  MyThread 线程:

 package com.test.threadDemo1;

 public class MyThread2 implements Runnable {

     public MyThread2(String name) {
Thread.currentThread().setName(name);
} @Override
public void run() {
for(int i=20;i<=100;i++) {
System.out.println(Thread.currentThread().getName()+"..."+i);
}
} }

  main 线程:

 package com.test.threadDemo1;
/**
* 多线程的实现之二:实现 Runable 接口
* @author Administrator
*
*/
public class ThreadDemo2 {
public static void main(String[] args) {
for (int i=1;i<=100;i++) {
System.out.println(Thread.currentThread().getName()+"..."+i); if(i==30) {
MyThread2 myThread = new MyThread2("新线程"); Thread thread = new Thread(myThread); thread.start();
}
}
}
}

  运行结果:

  

4.3 实现 Callable 接口和 Future 接口

  Future接口的实现类是 FutureTask,它实现了 Runable 接口,所以能够作为 target 参数传到 Thread 类的构造方法里。

  FutureTask(Callable<V> callable)

  从构造方法里可以看出 FutureTask 的构造方法里传入 callable 的实现类就行了。

  MyThread3 线程:

 package com.test.threadDemo1;

 import java.util.concurrent.Callable;

 public class MyThread3 implements Callable<Integer> {

     @Override
public Integer call() throws Exception {
int i = 20;
for(;i<=100;i++) {
System.out.println(Thread.currentThread().getName()+"..."+i);
}
return i;
} }

  main 线程:

 package com.test.threadDemo1;

 import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask; /**
* 多线程的实现之三:实现 Callable 接口和 Future 接口
* @author Administrator
*
*/
public class ThreadDemo3 {
public static void main(String[] args) { Callable<Integer> myThread3 = new MyThread3();
FutureTask<Integer> task = new FutureTask<Integer>(myThread3); for (int i=1;i<=100;i++) {
System.out.println(Thread.currentThread().getName()+"..."+i); if(i==30) { Thread thread = new Thread(task,"新线程");
thread.start();
}
}
}
}

  运行结果:

  

【java多线程】多线程的创建三种方式--笔记的更多相关文章

  1. java 实现md5加密的三种方式与解密

      java 实现md5加密的三种方式 CreateTime--2018年5月31日15点04分 Author:Marydon 一.解密 说明:截止文章发布,Java没有实现解密,但是已有网站可以免费 ...

  2. Java 实现线程安全的三种方式

    一个程序在运行起来的时候会转换成进程,通常含有多个线程. 通常情况下,一个进程中的比较耗时的操作(如长循环.文件上传下载.网络资源获取等),往往会采用多线程来解决. 比如显示生活中,银行取钱问题.火车 ...

  3. java实现HTTP请求的三种方式

    目前JAVA实现HTTP请求的方法用的最多的有两种:一种是通过HTTPClient这种第三方的开源框架去实现.HTTPClient对HTTP的封装性比较不错,通过它基本上能够满足我们大部分的需求,Ht ...

  4. 【转载】java实现HTTP请求的三种方式

    目前JAVA实现HTTP请求的方法用的最多的有两种:一种是通过HTTPClient这种第三方的开源框架去实现.HTTPClient对HTTP的封装性比较不错,通过它基本上能够满足我们大部分的需求,Ht ...

  5. HTTP:Java实现HTTP请求的三种方式

    目前JAVA实现HTTP请求的方法用的最多的有两种: 一种是通过HTTPClient这种第三方的开源框架去实现.HTTPClient对HTTP的封装性比较不错,通过它基本上能够满足我们大部分的需求,H ...

  6. java中遍历集合的三种方式

    第一种遍历集合的方式:将集合变为数组 package com.lw.List; import java.util.ArrayList; import java.util.List; import ja ...

  7. java加载配置文件的三种方式

    比如我们要加载db.properties文件 如图: 比如我们要加载source目录下的db.properties文件.就有以下几种方式 第一种是文件io流: public static void l ...

  8. JAVA实现Base64编码的三种方式

    摘要: Javabase64编码的三种方式   有如下三种方式: 方式一:commons-codec.jar Java代码  1. String base64String="whuang12 ...

  9. Java通过JDBC连接数据库的三种方式!!!并对数据库实现增删改查

    前言 java连接数据库完整流程为: 1,获得驱动(driver),数据库连接(url),用户名(username),密码(password)基本信息的三种方式. 2,通过获得的信息完成JDBC实现连 ...

随机推荐

  1. 微信获取ticket及生成二维码(临时或永久)

    微信获取ticket及生成二维码(临时或永久) curl.php---- define("APPID",""); define("APPSECRET& ...

  2. VB中StdPicture尺寸(Width,Height)转像素单位

    首先获得一个图片对象 Dim spic As StdPicture Set spic = LoadPicture("d:\0.bmp") '从文件获得 Set spic = Cli ...

  3. js计算发表的时间...分钟/小时以前/以后

    网上找的都好复杂,这本来就是个粗略显示通俗的时间,绕来绕去都晕了 function timeAgo(o){ var n=new Date().getTime(); var f=n-o; var bs= ...

  4. 创建一个git仓库

    1.git init 使用git init命令初始化一个git仓库,git仓库会生成一个.git目录 git init 1.使用指定的目录作为我们的git仓库 git init newrepo 2.初 ...

  5. EF CodeFirst类生成器

    前段时间由于用到EF Code First. 上头让我添加一个功能,然后....要映射12张表到实体类中... 太无语了吧...一张表30多个字段啊老大!!!! "有没有工具可以快速弄啊,自 ...

  6. ASP.NET MVC 网页应用 action 传递的Model

    视图界面 @using {引用模型} @model {具体模型} <html> @Model.{具体模型的属性} </html> 注意区分Model的大小写 引入时,使用@mo ...

  7. vue项目中引入mint-ui的方式(全部引入与按需引入)

    参考哦 https://blog.csdn.net/qq_36742720/article/details/83620584 https://jingyan.baidu.com/article/c1a ...

  8. c++编译错误C2971:"std::array":array_size:包含非静态存储不能用作废类型参数;参见“std::array”的声明

    在Qt5中这段代码编写有两种方式:一个编译成功,一个失败 成功版本: static constexpr size_t block_size = 0x2000;//8KB static constexp ...

  9. python从入门到实践-10章文件和异常(括号问题)

    #!/user/bin/env python# -*- coding:utf-8 -*- # 1.从文件中读取数据with open('pi_digits.txt') as file_object: ...

  10. 权限系统设计-day01

    数据库表的设计:   关键流程思考: 权限在SSH系统中应该表现为什么东西? 小胖这个用户登陆:1,检查用户名和密码;2,检查通过; 1),得到小胖这个用户的对应的所有的角色:R1 2),根据所有的角 ...