多线程01(二)

简介: 多线程01

3.3变形写法.

  • 说明:在有时候我们只是临时使用一次线程,此时就没必要专门定义线程类,浪费资源。那么我们就可以通过以下两种写法实现多线程。

3.3.1在同一个文件里面创建Thread子类.


3.3.2匿名内部类.

补充lambda表达式写法。


3.4注意事项.

  1. 子线程之间的运行时随机的,到底运行谁,由CPU分配时间片决定。
  2. 不是main线程执行结束后才执行子线程。程序是先从main方法开始执行的(即从main线程开始执行),如果main方法里执行了其他线程的start方法,其它线程就会进入就绪状态,这时就看CPU分配时间片给谁,谁就执行。
  3. 如果自己手动通过线程对象调用run()方法,那么就只是调用一个普通方法,没有启动多线程模式。  
  4. run()方法由JVM调用,什么时候调用,执行的过程控制都有操作系统的CPU调度决定。  
  5. 想要启动多线程,必须调用start方法。  
  6. 一个线程对象只能调用一次start()方法启动,如果重复调用了,则将抛出异常“IllegalThreadStateException”

4.实现Runable接口方式.

  • Java有单继承的限制,当我们无法继承Thread类时,那么该如何做呢?在核心类库中提供了Runnable接口,我们可以实现Runnable接口,重写run()方法,然后再通过Thread类的对象代理启动和执行我们的线程体run()方法。

4.1使用步骤.

  1. 定义Runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
  2. 创建Runnable实现类的实例,并以此实例作为Thread的target参数(线程要执行的内容)来创建Thread对象,该Thread对象才是真正的线程对象。
  3. 调用线程对象的start()方法,启动线程。调用Runnable接口实现类的run方法。

4.2代码演示.

  • 定义Runnable接口实现类.

  • 测试:


4.3变形写法.

4.3.1在同一个文件里面创建Runnable接口实现类.


4.3.2匿名内部类方式.

  • 写法一:未使用Lambda表达式。

  • 写法二:使用Lambda表达式。


4.4注意事项.

  1. 通过实现Runnable接口,使得该类有了多线程类的特征。所有的分线程要执行的代码都在run方法里面。
  2. 在启动的多线程的时候,需要先通过Thread类的构造方法Thread(Runnable target) 构造出对象,然后调用Thread对象的start()方法来运行多线程代码。
  3. 实际上,所有的多线程代码都是通过运行Thread的start()方法来运行的。因此,不管是继承Thread类还是实现Runnable接口来实现多线程,最终还是通过Thread的对象的API来控制线程的,熟悉Thread类的API是进行多线程编程的基础。
  4. 说明:Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run()方法仅作为线程执行体。可以理解为 Runnable对象就是一个数据体,里面包含了线程要执行的内容。而实际的线程对象依然是Thread实例,只是该Thread线程负责执行其target的run()方法。

5.继承Thread类和实现Runnable接口两种方式对比.

  1. Thread类实际上也是实现了Runnable接口的类。
  2. 继承Thread方式适合线程之间处理各自任务(不共享资源)情况。
  3. 实现Runnable接口比继承Thread类所具有的优势:
  1. 避免了单继承的局限性;
  2. 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源;
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。

6.相关方法.

6.1设置线程名.

  • 不设置线程名,默认是:Thread-0、Thread-1、Thread-2....这样命名。可以在线程的 run方法里面获取当前线程名测试 :Thread.currentThread().getName()
  • 手动设置线程名:
  • 继承Thread类方式:
  • 通过创建的线程对象调用:setName("线程名");方法进行设置;
  • 在线程类里面定义带参构造函数,然后调用父类构造函数。如:

  • 实现Runnable接口方式:


6.2设置线程休眠- .

  1. Thread.sleep():是Thread类的一个静态方法。作用:使当前线程休眠,进入阻塞状态(暂停执行),简单理解就是“线程暂停方法”。该方法可接收长整型毫秒和整型纳秒,可读性差(因为需要根据毫秒数或者纳秒数换算成其它时间单位)。
  2. TimeUnit.SECONDS.sleep():是 concurrent 包下的一个类,提供了可读性更好的线程暂停操作。里面提供了很多枚举类,如:

枚举

单位

DAYS

HOURS

小时

MINUTES

分钟

SECONDS

MILLISECONDS

毫秒(千分之一秒)

MICROSECONDS

微秒(一百万分之一秒(就是毫秒/1000))

NANOSECONDS

毫微秒(十亿分之一秒(就是微秒/1000))

  • 使用方式如下:

  • 除了枚举之外可以进行时间转换:


6.3设置&获取线程优先级.

  • getPriority() :返回线程优先级;
  • setPriority(int newPriority) :改变线程的优先级,范围在[1,10]之间。

6.4join方法.

  • join方法的作用是:在当前 线程执行的某个阶段,加入并执行其它线程。

  • 案例:


6.5yield方法.

  • yield方法的作用是当前正在运行的线程放弃CPU资源,重新回到就绪状态.
  • 案例:


6.6stop方法.

  • stop():已过时,不建议使用。强行杀死执行,直接进入死亡状态。run()即刻停止,可能会导致一些清理性的工作得不到完成,如文件,数据库等的关闭。同时,会立即释放该线程所持有的所有的锁,导致数据得不到同步的处理,出现数据不一致的问题。比如转账转了一半,突然停止。
  • 案例演示:

  • 运行结果:

  • 当线程2运行到第10次的时候就会暴力停止线程1的运行。但是从结果上发现,当线程2运行完第10次后,线程1又运行了一次,然后才被停止的,这是因为当线程2执行完第10次的输出语句后,还没来得及执行暴力停止线程1的代码,CPU马上给线程1分配时间片,线程1运行,然后CPU再给线程2分配时间片,线程2运行,马上暴力停止线程1.
  • 这样会导致线程1在停止的时候没有来得及处理后事,不安全。就好比,你在工厂里面生成产品,别人突然叫你停止生产,连给你关闭设备的时间都没有留。正确的应该是先提前通知你要停止生产了,给你时间关闭设备。

相关文章
|
7月前
|
消息中间件 前端开发
C++11多线程相关
C++11多线程相关
60 0
|
8月前
|
Java
|
9月前
65.【 多线程2】(一)
65.【 多线程2】
26 0
|
9月前
65.【 多线程2】(三)
65.【 多线程2】
32 0
|
9月前
65.【 多线程2】(二)
65.【 多线程2】
30 0
|
29天前
|
安全 Java C++
多线程问题(四)
多线程问题(四)
21 0
|
30天前
|
设计模式 安全 Java
多线程问题(三)
多线程问题(三)
24 0
|
1月前
|
Java API 调度
多线程知识篇
多线程知识篇
|
8月前
|
Java
多线程
java多线程是指在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。Java中所有变量都储存在主存中,对于所有线程都是共享的。Java中的多线程可以通过继承Thread类或者实现Runnable接口来创建,然后通过start()方法来启动线程。Java中的多线程可以提高程序的并发性和执行效率。
|
10月前
|
监控 Java API
多线程专题
多线程专题