你好,我是goldsunC

让我们一起进步吧!

线程的控制与同步

线程的状态与生命周期

‘每个Java程序都有一个默认的主线程,想要实现多线程,必须在主线程中创建新的线程对象。新建的线程在它的一个完整的生命周期中通常要经历如下的五种状态:新建(New):当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。这个时候它已经有了相应的内存空间或其它资源,并已被初始化。

就绪(Runnable):处于新建状态的线程被启动后,将进入线程队列排队等待CPU的时间片,这个时候它已经具备了运行的条件。一旦轮到它来享用CPU资源时,就可以脱离创建它的主线程独立,开始自己的生命周期。另外,原来处于阻塞状态的线程被解除阻塞后也将进入就绪状态。

运行(Running):当就绪状态的线程被调度并获得CPU资源时,便进入运行状态。每一个Thread及其子类的对象都有一个run()方法,当线程对象被调度执行时,它将自动调用对象的run()方法,从第一句开始顺次执行。run()方法中定义了这一类线程的操作和功能。

阻塞(Blocked):一个正在执行的线程在某些特殊情况下,如果被人为挂起或需要执行费时的I/O操作时,将会让出CPU资源并暂时中止自己的执行,进入阻塞状态。阻塞状态时,它不能进入排队队列。只有当引起阻塞的原因被消除后,线程才可以转入就绪状态,重新进到线程队列中排队等待CPU资源,以便在原来终止出从新开始运行。

终止(Dead):处于终止(死亡)状态的线程不再具有继续运行的能力。线程死亡的原因有两个:正常运行的线程完成了它的全部工作。

被强制性的提前终止,比如通过执行destroy()终止线程。

线程的基本控制

结束线程

之前我们可以用Thread对象的stop()方法来结束线程,不过现在这个方法已经不主张用了,因为它是不安全的。现在我们要结束一个线程往往通过设定一个标记变量的方法来决定线程是否应该终止。

如下一个示例:

import java.util.Date;

class Timer implements Runnable {

boolean flag = true;

@Override

public void run() {

while (flag) {

System.out.print("\r\t" + new Date() + "...");

try {

Thread.sleep(1000);

}catch (InterruptedException e ) {}

}

System.out.println("\n" + Thread.currentThread().getName() + "Stop");

}

public void stopRun() {

flag = false;

}

}

public class ThreadTerminateByFlag {

public static void main(String[] args ) {

Timer timer = new Timer();

Thread thread = new Thread(timer);

thread.setName("Timer");

thread.start();

for (int i=0; i<100; i++) {

System.out.print("\r" + i);

try {

Thread.sleep(100);

}catch (InterruptedException e) {}

}

timer.stopRun();

}

}

如上示例通过设定flag变量来提前结束线程循环。

暂时阻止线程执行

之前我们可以通过线程的suspend()方法来暂时阻止线程的执行,用resume()方法来恢复线程执行,不过现在这两个方法也不主张用了,目前的常用方法有以下两种:sleep():在上一个示例我们已经用过这个方法了,用Thread.sleep(long millisecond)来暂时挂起线程。

其基本使用方法即:

try {

Thread.sleep(1000); //时间参数可以自行设定

}catch( InterruptedException e) {

//...

}join():调用某线程的join()方法,可以将一个线程加入到本线程中,本线程的执行会等待另一线程执行完毕。

其基本使用方法如下:

Thread t; //t是另一线程

try {

t.join();

}catch( InterruptedException e) {

//...

}

jion()方法可以不带参数,也可以带上一个long参数,表示等待的最长时间。

如下一个示例:

class Runner implements Runnable {

@Override

public void run() {

for (int i=0 ; i<10; i++) {

System.out.println(i);

try {

Thread.sleep(100);

}catch (InterruptedException e) {}

}

}

}

public class ThreadJoin {

public static void main(String[] args) {

Runner runner = new Runner();

Thread thread = new Thread(runner);

thread.start();

try {

thread.join();

}catch (InterruptedException e) {}

for (int i=0; i<10; i++) {

System.out.println("\t" + i);

try {

Thread.sleep(100);

}catch (InterruptedException e) {}

}

}

}

OUT:(输出如下,使用join) OUT:(不使用join)

0 0

1 0

2 1

3 1

4 2

5 2

6 3

7 3

8 4

9 4

0 5

1 5

2 6

3 6

4 7

5 7

6 8

7 8

8 9

9 9yield():Thread对象的yield()方法可以给其它线程以执行的机会,如果没有其它可以运行的线程,则该方法不产生任何作用。

设定线程的优先级

处于就绪状态的线程首先进入就绪队列排队等候处理器资源。同一时间在就绪队列中的线程可能有多个,它们各自任务的轻重缓急程度不同。为了体现上述差别,使工作安排得更加合理,多线程系统会给每个线程自动分配一个线程的优先级(Priorty),任务较紧急重要的线程,其优先级就较高,相反则较低。

同时处于就绪状态的线程,优先级高的,有优先被调度的权利。相同优先级,一般遵循先到先服务的原则,但也不一定十分严格。

Thread类有三个有关线程优先级的静态常量:MIN_PRIORITY:最小优先级,数值通常为1。

MAX_PRIORITY:最高优先级,数值通常为10。

NORM_PRIORITY:普通优先级,默认数值为5。

对于一个新建线程,系统会遵循如下原则为其指定优先级。新建线程的优先级将继承创建它的父线程的优先级。父线程是指执行创建新线程对象语句的线程,它可能是程序的主线程,也可能是某一个用户自定义的线程。

一般情况下主线程拥有普通优先级。用户可以通过调用Thread类的方法setPriority()来修改系统自动设定的线程优先级,使之更符合程序的特定需要。

为线程设定不同的优先级查看实现效果,如下一个示例:

class PriorityRunner implements Runnable {

int id;

PriorityRunner(int id) {

this.id = id;

}

@Override

public void run() {

for (int i=0; i<100; i++) {

if (i%100 ==0) System.out.print("\r");

Thread.currentThread().yield();

System.out.print(id);

}

}

}

public class TestThreadPriority {

public static void main(String[] args) {

Thread t1 = new Thread(new PriorityRunner(1));

Thread t2 = new Thread(new PriorityRunner(2));

Thread t3 = new Thread(new PriorityRunner(3));

t1.setPriority(Thread.MIN_PRIORITY);

t2.setPriority(Thread.NORM_PRIORITY);

t3.setPriority(Thread.MAX_PRIORITY);

t1.start();

t2.start();

t3.start();

}

}

Daemon线程

线程有两种,一类是Daemon线程,也叫后台线程或者守护线程。另一类是非Daemon线程。在Java程序中,如果还有非守护线程,整个程序就不会结束,如果正在运行的线程都是守护线程,Java虚拟机会退出,也就是主线程会强制结束守护线程。

将一个线程设置为守护线程,可以使用setDaemon(true)方法。

垃圾回收线程就是优先级很低的守护线程。如果没有其它非守护线程了,主线程会强制结束垃圾回收线程,Java虚拟机退出。

在一个程序中其实经常会有守护线程,比如玩一些游戏的背景音乐线程,它们就是守护线程,打开游戏背景音乐就会开始,如果游戏主线程结束那么背景音乐就会关闭。

如下一个示例使用Daemon线程:

import java.util.Date;

class MyThread extends Thread {

@Override

public void run() {

for (int i=0; i<10; i++) {

System.out.println(i + "--" + new Date());

try {

Thread.sleep(100);

}catch (InterruptedException e) {}

}

}

}

public class TestThreadDaemon {

public static void main(String[] args) {

Thread thread = new MyThread();

thread.setDaemon(true);

thread.start();

System.out.println("Main--" + new Date());

try {

Thread.sleep(500);

}catch (InterruptedException e) {}

System.out.println("Main End");

}

}

OUT(输出):

Main--Sat Oct 31 19:06:23 GMT+08:00 2020

0--Sat Oct 31 19:06:23 GMT+08:00 2020

1--Sat Oct 31 19:06:23 GMT+08:00 2020

2--Sat Oct 31 19:06:23 GMT+08:00 2020

3--Sat Oct 31 19:06:23 GMT+08:00 2020

4--Sat Oct 31 19:06:23 GMT+08:00 2020

Main End

如上所示,主线程只运行了500ms,而Daemon线程在显示5行后就被停止了。

java 同步转并行_Java线程与并行编程(二)相关推荐

  1. java同步与死锁_Java多线程 - 线程同步与死锁

    一.线程同步 1)模拟多个用户同时从银行账户里面取钱 ● Account 类:银行账户类,里面有一些账户的基本信息,以及操作账户信息的方法 //模拟银行账户 classAccount {private ...

  2. java 同步块原理_Java同步代码块和同步方法原理与应用案例详解

    Java同步代码块和同步方法原理与应用案例详解 发布于 2020-8-7| 复制链接 摘记: 本文实例讲述了Java同步代码块和同步方法.分享给大家供大家参考,具体如下:一 点睛所谓原子性:一段代码要 ...

  3. java 同步块关键字_Java同步关键字,同步方法和块

    java 同步块关键字 Java synchronized keyword is used in multithreading to create a code block that can be e ...

  4. auto.js停止所有线程_Java线程与并发编程实践:深入理解volatile和final变量

    同步有两种属性:互斥性和可见性.synchronized关键字与两者都有关系.Java同时也提供了一种更弱的.仅仅包含可见性的同步形式,并且只以volatile关键字关联. 假设你自己设计了一个停止线 ...

  5. java多线程 门闩_Java线程与并发编程实践----同步器(倒计时门闩,同步屏障)...

    Java提供的synchronized关键字对临界区进行线程同步访问.由于基于synchronized很难 正确编写同步代码,并发工具类提供了高级的同步器.倒计时门闩(countdown latch) ...

  6. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  7. java 同步块 抛出异常_java问题合集(一)

    垃圾回收算法 引用计数法,标记清除法,标记压缩清除法(Java中老年代采用),复制算法(Java中新生代采用),分代法(Java堆采用),分区算法. 重要的三句话: 垃圾回收器只知道释放那些经由new ...

  8. java同步锁实例_Java lock同步锁使用实例解析

    这篇文章主要介绍了Java lock同步锁使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1)Lock是一个接口,而synchroniz ...

  9. java同步锁售票_线程同步锁之火车站售票案例

    前言: 谈到多线程,就不得不说线程同步,那么什么是线程同步? 线程同步 即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作 ...

最新文章

  1. Linux下Apache虚拟主机配置
  2. Matlab中disp、fprintf和sprintf
  3. mysql5.7命中率_MySQL5.7中 performance和sys schema中的监控参数解释(推荐)
  4. 神器 Nginx 的学习手册 ( 建议收藏 )
  5. oracle的共享内存段,oracle共享内存段手工清理
  6. STM32F103自定义的printf函数的实现
  7. 物联网大数据的爆发只是一个开始
  8. 如何检查PHP数组是关联数组还是顺序数组?
  9. 修改windows默认远程管理端口
  10. Kodak Preps 8 for Mac中文破解版永久激活教程
  11. 枯竭的水库求生的稻田 国稻种芯·九江:位于抗旱一线的都昌
  12. 眼花缭乱中看Metro Style—MS Apps Store—Desktop Apps以及Win-Runtime和Win32
  13. 取小数点后两位(解析)
  14. Spring Cloud--Sleuth+Zipkin 链路跟踪/订单的流量削峰
  15. 长为一名JAVA架构师2017-10-16 2
  16. 睿普康 以太网接口PHY芯片主要替换瑞昱的pin对pin芯片
  17. 美工(一)网页颜色搭配技巧 文字字体、字号、字体排版等
  18. java.lang.NullPointerException出现的几种原因以及解决
  19. 通过注册表删除软件自动生成的设备和驱动器
  20. seo专用推送神器免费使用

热门文章

  1. Linux内核--1,2章
  2. 自己对多线程的一点思考
  3. linux grep 点号的匹配
  4. docker 可视化管理工具 rancher 简介
  5. linux c 取消宏定义
  6. linux elf 文件查看工具 readelf
  7. linux信号(signal) 机制分析
  8. Android中自定义控件
  9. Openstack在controller节点 nova image-list HTTP500
  10. QEMU 使用的镜像文件:qcow2 与 raw