当前位置: 首页 > 编程日记 > 正文

Java并发编程(一)Thread详解

一、概述

在开始学习Thread之前,我们先来了解一下 线程和进程之间的关系:

线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位。 线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。

由上描述,可以得知线程作为cpu的基本调度单位,只有把多线程用好,才能充分利用cpu的多核资源。

本文基于JDK 8(也可以叫JDK 1.8)。

二、线程使用

2.1 启动线程

创建线程有四种方式:

  • 实现Runnable接口
  • 继承Thread类
  • 使用JDK 8 的Lambda
  • 使用Callable和Future

2.1.1 Runnable创建方式

public class MyThread implements Runnable {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}
Thread thread = new Thread(new MyThread());
thread.start();

2.1.2 继承Thread创建方式

public class MyThread extends Thread{@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}
MyThread thread = new MyThread();
thread.start();

以上代码有更简单的写法,如下:

Thread thread = new Thread(){@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
};
thread.start();

2.1.3 Lambda创建方式

new Thread(()-> System.out.println(Thread.currentThread().getName())).start();

2.1.4 使用Callable和Future

看源码可以知道Thread的父类是Runnable是JDK1.0提供的,而Callable和Runnable类似,是JDK1.5提供的,弥补了调用线程没有返回值的情况,可以看做是Runnable的一个补充,下面看看Callable的实现。

public class MyThread implements Callable<String> {@Overridepublic String call() throws Exception {System.out.println(Thread.currentThread().getName());return Thread.currentThread().getName();}
}
Callable<String> callable = new MyThread();
FutureTask<String> ft = new FutureTask<>(callable);
new Thread(ft,"threadName").start();
System.out.println(ft.get());

2.1.5 run()和start()的区别

真正启动线程的是start()方法而不是run(),run()和普通的成员方法一样,可以重复使用,但不能启动一个新线程。

2.2 Thread的常用方法

Thread类方法

方法说明
start()启动线程
setName(String name)设置线程名称
setPriority(int priority)设置线程优先级,默认5,取值1-10
join(long millisec)挂起线程xx毫秒,参数可以不传
interrupt()终止线程
isAlive()测试线程是否处于活动状态

Thread静态(static)方法

方法说明
yield()暂停当前正在执行的线程对象,并执行其他线程。
sleep(long millisec)/sleep(long millis, int nanos)挂起线程xx秒,参数不可省略
currentThread()返回对当前正在执行的线程对象的引用
holdsLock(Object x)当前线程是否拥有锁

2.3 sleep()和wait()的区别

sleep为线程的方法,而wait为Object的方法,他们的功能相似,最大本质的区别是:sleep不释放锁,wait释放锁。

用法上的不同:sleep(milliseconds)可以用时间指定来使他自动醒过来,如果时间不到你只能调用interreput()来终止线程;wait()可以用notify()/notifyAll()直接唤起。

重点: 测试wait和sleep释放锁的代码如下:

public class SynchronizedTest extends Thread {int number = 10;public synchronized void first(){System.out.println("this is first!");number = number+1;}public synchronized void secord() throws InterruptedException {System.out.println("this is secord!!");Thread.sleep(1000);
//        this.wait(1000);number = number*100;}@Overridepublic void run() {first();}
}
SynchronizedTest synchronizedTest = new SynchronizedTest();
synchronizedTest.start();
synchronizedTest.secord();
// 主线程稍等10毫秒
Thread.sleep(10);
System.out.println(synchronizedTest.number);

根据结果可以得知:

  • 执行sleep(1000)运行的结果是:1001
  • 执行wait(1000)运行的结果是:1100

总结: 使用 sleep(1000)不释放同步锁,执行的是10*100+1=1001,wait(1000)释放了锁,执行的顺序是(10+1)x100=1100,所以sleep不释放锁,wait释放锁。

三、线程状态

3.1 线程状态概览

线程状态:

  • NEW 尚未启动
  • RUNNABLE 正在执行中
  • BLOCKED 阻塞的(被同步锁或者IO锁阻塞)
  • WAITING 永久等待状态
  • TIMED_WAITING 等待指定的时间重新被唤醒的状态
  • TERMINATED 执行完成

线程的状态可以使用getState()查看,更多状态详情,查看Thread源码,如下图:

3.2 线程的状态代码实现

3.2.1 NEW 尚未启动状态

Thread thread = new Thread() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
};
// 只声明不调用start()方法,得到的状态是NEW
System.out.println(thread.getState()); // NEW

3.2.2 RUNNABLE 运行状态

Thread thread = new Thread() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
};
thread.start();
System.out.println(thread.getState()); // RUNNABLE

3.2.3 BLOCKED 阻塞状态

使用synchronized同步阻塞实现,代码如下:

public class MyCounter {int counter;public synchronized void increase()  {counter++;try {Thread.sleep(10*1000);} catch (InterruptedException e) {e.printStackTrace();}}
}
MyCounter myCounter = new MyCounter();
// 线程1调用同步线程,模拟阻塞
new Thread(()-> myCounter.increase()).start();
// 线程2继续调用同步阻塞方法
Thread thread = new Thread(()-> myCounter.increase());
thread.start();// 让主线程等10毫秒
Thread.currentThread().sleep(10);
// 打印线程2,为阻塞状态:BLOCKED
System.out.println(thread.getState());

3.2.4 WAITING 永久等待状态

public class MyThread extends Thread{@Overridepublic void run() {synchronized (MyThread.class){try {MyThread.class.wait();System.out.println(Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}}
}
Thread thread = new Thread(new MyThread());
thread.start();
// 主线程挂起200毫秒,等thread执行完成
Thread.sleep(200);
// 输出WAITING,线程thread一直处于被挂起状态
System.out.println(thread.getState());

唤醒线程: 可使用 notify/notifyAll 方法,代码如下:

synchronized (MyThread.class) {MyThread.class.notify();
}

使线程WAITING的方法:

  • Object的wait() 不设置超时时间
  • Thread.join()不设置超时时间
  • LockSupport的park()

查看Thread源码可以知道Thread的join方法,底层使用的是Object的wait实现的,如下图:

注意: 查看Object的源码可知wait(),不传递参数,等同于wait(0),设置的“0”不是立即执行,而是无限的等待,不执行,如下图:

3.2.5 TIMED_WAITING 超时等待状态

TIMED_WAITING状态,只需要给wait设置上时间即可,代码如下:

public class MyThread extends Thread{@Overridepublic void run() {synchronized (MyThread.class){try {MyThread.class.wait(1000);System.out.println(Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}}}
}

调用代码还是一样的,如下:

Thread thread = new Thread(new MyThread());
thread.start();
// 主线程挂起200毫秒,等thread执行完成
Thread.sleep(200);
// 输出TIMED_WAITING
System.out.println(thread.getState());
synchronized (MyThread.class) {MyThread.class.notify();
}

3.2.6 TERMINATED 完成状态

Thread thread = new Thread(()-> System.out.println(Thread.currentThread().getName()));
thread.start();
// 让主线程等10毫秒
Thread.currentThread().sleep(10);
System.out.println(thread.getState());

四、死锁

根据前面的知识,我们知道使用sleep的时候是不释放锁的,所以利用这个特性我们可以很轻易的写出死锁的代码,具体的流程如图(图片来源于杨晓峰老师文章):

代码如下:

static  Object object1 = new Object();
static  Object object2 = new Object();public static void main(String[] args) {Thread thread = new Thread(){@Overridepublic void run() {synchronized (object1){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (object2){System.out.println(Thread.currentThread().getName());}}}};Thread thread2 = new Thread(){@Overridepublic void run() {synchronized (object2){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (object1){System.out.println(Thread.currentThread().getName());}}}};thread.start();thread2.start();

运行上面的代码,程序会处于无限等待之中。

五、总结

根据上面的内容,我们已经系统的学习Thread的使用了,然而学而不思则罔,最后留一个思考题:根据本文介绍的知识,怎么能避免死锁?(哈哈,卖个关子,根据文章的知识点组合可以得出答案)

源码下载:https://github.com/vipstone/j...


推荐部分

本人最近看了前Oracle首席工程师杨晓峰的课程,也是第四部分引用的流程图的主人,感觉很不错,推荐给你,一起来系统的学习Java核心吧。

参考文档

https://docs.oracle.com/javas...

相关文章:

MFC如何打开文件路径

转自&#xff1a;http://linyangmumu.blog.163.com/blog/static/6903134920101024419380/ 1.void OpenFile&#xff08;&#xff09; { CString m_FileDir; BROWSEINFO bi; ZeroMemory(&bi, sizeof(BROWSEINFO)); bi.hwndOwner m_hWnd; bi.ulFlags BIF_RETURNONL…

HDOJ_ACM_数塔

Problem Description在讲述DP算法的时候&#xff0c;一个经典的例子就是数塔问题&#xff0c;它是这样描述的&#xff1a;有如下所示的数塔&#xff0c;要求从顶层走到底层&#xff0c;若每一步只能走到相邻的结点&#xff0c;则经过的结点的数字之和最大是多少&#xff1f;已经…

会数据分析的人别再低调了,我怕你会因此错失100万奖金

大家好我是一般周一不冒头一冒头就不一般的柚柚今天我给大家带来了一个好消息那就是“易观方舟Argo杯数据创客大赛”开始接受报名了&#xff01;请不要怀疑就是那个国内领先的大数据公司——『易观』联合20家创新企业筹备了整整两个月的大赛正规、专业、含金量极高&#xff01;…

CxImage类库的简介

转自&#xff1a;http://www.sudu.cn/info/html/edu/20080403/259688.html CxImage类库是个优秀的图像操作类库。他能快捷地存取、显示、转换各种图像。有的读者可能说&#xff0c;有那么多优秀的图像库&#xff0c;如OpenIL,FreeImage,PaintLib等等&#xff0c;他们可谓是功能…

MySQL 5.5 服务器变量详解(二)

innodb_adaptive_flushing{ON|OFF} 设定是否允许MySQL服务器根据工作负载动态调整刷写InnoDB buffer pool中的脏页的速率。动态调整刷写速率的目的在于避免出现IO活动尖峰。默认值为ON。作用范围为全局级别&#xff0c;可用于选项文件&#xff0c;属动态变量。innodb_adaptive_…

一文掌握异常检测的实用方法 | 技术实践

作者 | Vegard Flovik译者 | Tianyu责编 | Jane出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;【导读】今天这篇文章会向大家介绍几个有关机器学习和统计分析的技术和应用&#xff0c;并展示如何使用这些方法解决一些具体的异常检测和状态监控实例。相信对一些开发…

票据自动处理系统著名研究团队

国际上对票据自动处理系统的研究始于上世纪80年代&#xff0c;俄罗斯、美国、加拿大、日本、巴西等国在这个领域的研究工作开展得比较深入&#xff0c;著名的研究团体如加拿大Concordia大学的CENPARMI中心、MIT的PROFIT实验室、俄罗斯ABBYY软件公司、Mitek Systems公司CheckQue…

iOS开发之AVKit框架使用

2019独角兽企业重金招聘Python工程师标准>>> iOS开发之AVKit框架使用 一、引言 在iOS开发框架中&#xff0c;AVKit是一个非常上层&#xff0c;偏应用的框架&#xff0c;它是基于AVFoundation的一层视图层封装。其中相关文件和类都十分简单&#xff0c;本篇博客主要整…

DirectX10 学习笔记2:在多文档框架中初始化DirectX 10

显示功能是在视图类中完成的&#xff0c;所以DX10的初始化及绘制工作都是视图类中完成。 首先建立一个多文档工程&#xff0c;工程名为02_01&#xff0c;在视图类头文件中加载相关的库&#xff0c;并包含头文件&#xff1a; 在视图类的头文件中添加DX10相关的成员&#xff1a; …

碾压Bert?“屠榜”的XLnet对NLP任务意味着什么

作者张俊林&#xff0c;中国中文信息学会理事&#xff0c;中科院软件所博士。目前担任新浪微博机器学习团队 AI Lab 负责人。在此之前&#xff0c;张俊林曾经在阿里巴巴任资深技术专家并负责新技术团队&#xff0c;以及在百度和用友担任技术经理及技术总监等职务。他是技术书籍…

ORACLE中通过DBMS_CRYPTO包对表敏感字段进行加密

http://doc.primeton.com/pages/viewpage.action?pageId4917998

02 使用百度地图获得当前位置的经纬度

O 需求 通过百度地图&#xff0c;获取用户当前位置的经纬度 一 准备 确保你已按照上篇《01 如何将百度地图加入IOS应用程序&#xff1f;》完成了相关功能。本篇将在上一篇的基础上进行修改。 二 编码 (New标示本次新添加的代码&#xff1b;Delete表示本次需要删除的代码&#x…

中文NLP的分词真有必要吗?李纪为团队四项任务评测一探究竟 | ACL 2019

作者| Yuxian Meng、Xiaoya Li、Xiaofei Sun、Qinghong Han、Arianna Yuan、 Jiwei Li译者 | Rachel责编 | Jane出品 | AI科技大本营&#xff08;ID: rgznai100&#xff09;【导读】通常&#xff0c;中文文本处理的第一步称为分词&#xff0c;这好像已经成为一种“共识”&#…

Netty 粘包 拆包 编码 解码 序列化 介绍

目录&#xff1a; 粘包 & 拆包及解决方案 ByteToMessageDecoder基于长度编解码器基于分割符的编解码器google 的 Protobuf 序列化介绍其他的前言 Netty 作为一个网络框架&#xff0c;对 TCP 连接中的问题都做了全面的考虑&#xff0c;比如粘包拆包导致的半包问题&#xff0…

matlab 全局变量

转自&#xff1a;http://matlab.net.cn/matlabjichu/2010/201005/265.html 如果你要多于一个函数共用一个简单的变量&#xff0c;简单的处理方法就是把这个变量在所有函数中定义为global全局变量。在命令行做同样的事情&#xff0c;如果你要工作空间访问上述变量。这个全局变量…

java 解决Html table的rowspan问题(osc处女作)

2019独角兽企业重金招聘Python工程师标准>>> 假如有如下html代码需要解析 <table border"1"><tr><td rowspan"3">1</td><td>1</td><td>1</td><td>1</td></tr><tr>&l…

基于C++的OpenCV常用函数

C版本的好处&#xff1a; 1、在于可以尽量避免使用指针这种危险的东西&#xff1b; 2、不用费心去release资源了&#xff0c;因为在其destructor里面&#xff0c;系统会自动帮你搞定。 3、在某些情况下会比C版本运行速度快。 在文件中包含 using namespace cv; 1. i…

基于GAN的图像水印去除器,效果堪比PS高手

作者 | 李翔转载自视说AI&#xff08;ID:techtalkai&#xff09;简介&#xff1a;李翔&#xff0c;国内某互联网大厂AI民工&#xff0c;前携程酒店图像技术负责人&#xff0c;计算机视觉和深度学习重度爱好者&#xff0c;在ICCV和CVPR等会议上发表论文十余篇。写在前面当前互联…

Flink最锋利的武器:Flink SQL入门和实战 | 附完整实现代码

作者 | 机智的王知无转载自大数据技术与架构&#xff08;ID: import_bigdata&#xff09;一、Flink SQL 背景Flink SQL 是 Flink 实时计算为简化计算模型&#xff0c;降低用户使用实时计算门槛而设计的一套符合标准 SQL 语义的开发语言。自 2015 年开始&#xff0c;阿里巴巴开始…

SQL SERVER中ROLLUP的用法

cube操作符 要使用cube&#xff0c;首先要了解group by 其实cube和rollup区别不太大&#xff0c;只是在基于group by 子句创建和汇总分组的可能的组合上有一定差别&#xff0c; cube将返回的更多的可能组合。如果在 group by 子句中有n个列或者是有n个表达式的话&#xff0c; s…

Mybait缓存机制

MyBatis同大多数ORM框架一样&#xff0c;提供了一级缓存和二级缓存的支持。 一级缓存&#xff1a;其作用域为session范围内&#xff0c;当session执行flush或close方法后&#xff0c;一级缓存会被清空。 二级缓存&#xff1a;二级缓存和一级缓存机制相同&#xff0c;但是可以自…

vs2008常用操作汇总

1、OpenCV2.1环境配置&#xff1a; (1)、Tools-->Options-->Projects and Solutions-->VCDrectories&#xff1a; Show directories for选择include files&#xff0c;加入目录 D:/Program Files/OpenCV2.1/include/opencv &#xff1b;Show directories for选择libra…

深度学习已至“瓶颈”?英特尔:数据处理是一剂良药

【导读】霍金弟子Alan Yuille在前不久发表言论称&#xff0c;至少在计算机视觉领域&#xff0c;深度学习的瓶颈已至。然而&#xff0c;人工智能与大数据的发展相辅相成&#xff0c;数据将会推动人工智能的发展&#xff0c;促进更多技术应用落地&#xff0c;将人工智能带入一个新…

WIN32 C++ 遍历文件夹

转自&#xff1a;http://blog.csdn.net/lizhigang770/archive/2010/11/30/6045242.aspx 一、先介绍一个结构 WIN32_FIND_DATA typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; // 文件属性 FILETIME ftCreationTime; // 文件创建时间 FILETIME ft…

UIView淡入淡出动画

小小原创&#xff0c;转载请注明出处&#xff1a;http://iphone.xiaoxiaostudio.net 如果你觉得为某个UIView 加载一个全新的View在这个UIView上面时&#xff0c;想要隐藏时setHidden显得太突兀了&#xff0c;我们可以给它增加一些动画&#xff0c;iOS上默认提供了一些动画&…

sass的继承,混合宏,占位符的用法总结

SCSS中混合宏使用 mixin mt($var){ margin-top: $var; }.block { include mt(5px);span { display:block; include mt(5px); } }extend如何工作 .icon {transition: background-color ease .2s;margin: 0 .5em;}.error-icon {extend .icon;/*错误图标指定的样式... */}.info-i…

js中cookie的使用详细分析

2019独角兽企业重金招聘Python工程师标准>>> JavaScript中的另一个机制&#xff1a;cookie&#xff0c;则可以达到真正全局变量的要求。 cookie是浏览器 提供的一种机制&#xff0c;它将document 对象的cookie属性提供给JavaScript。可以由JavaScript对其进行控制&a…

从事JAVA 20年最终却败给了Python,哭了!

之前遇到一个老师&#xff0c;他从事Java行业20年了&#xff0c;在Python兴起的时候&#xff0c;他周围的其他同行们都在纷纷学习Python方面的知识&#xff0c;连他的学生也问他“老师&#xff0c;你为什么不学Python呢&#xff1f;”。当这位听到学生这个问题的时候&#xff0…

c++删除文件夹

转自&#xff1a;http://blog.csdn.net/sshhbb/archive/2010/12/07/6061029.aspx c语言本身是不能删除文件或文件夹的&#xff0c;他们是windows操作系统里的东西&#xff0c;所以得借助其api函数。 其一&#xff1a;使用shell 接口&#xff1a; void FileDelete(CString di…

解决bootstrap下的图片自适应问题

.img-responsive {display: block; height: auto; max-width: 100%; }转载于:https://www.cnblogs.com/qjuly/p/9809910.html