Java的多线程1:线程的使用
概述
进程是线程的容器,线程共享进程的内存空间,所以线程之间彼此通信是比较容易的,而线程又有自己本地内存地址(jmm抽象概念,并不真实存在),其他线程无法访问。了解进程和线程关系,可以看我另一篇博客《进程与线程》
Java创建线程的两种方式
继承Thread类
public class ThreadDemo1 extends Thread {
@Override
public void run(){
for (int i = 0; i < 10; i++) {
System.out.println("当前执行的线程是" + Thread.currentThread().getName());
}
}
public static void main(String[] args) {
ThreadDemo1 threadDemo1 = new ThreadDemo1();
ThreadDemo1 threadDemo2 = new ThreadDemo1();
threadDemo1.start();
threadDemo2.start();
}
}
执行结果是不确定的

实现Runnable
public class ThreadDemo2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
for (int j = 0;j < 1000; ++j){
System.out.println(i + "当前执行的线程是" + Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
ThreadDemo2 threadDemo1 = new ThreadDemo2();
ThreadDemo2 threadDemo2 = new ThreadDemo2();
Thread thread1 = new Thread(threadDemo1);
Thread thread2 = new Thread(threadDemo2);
thread1.start();
thread2.start();
System.out.println("当前线程是===>" + Thread.currentThread().getName());
}
}
主线程的名字为main,非主线程的名字是由虚拟机来指定的,同时,我们也可以为线程指定具体的名称。

我们保证每个线程都能正常启动,并不意味着它会按顺序的执行,因为调度程序是无法保证它的执行次序的,同时,run()函数结束时,意味着该线程的任务完成了。
注意:调用线程要调用start,如果调用run,那仅仅是简单的对象调用。
线程生命周期

public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
新建状态
线程对象创建后,就进入新建状态 Thread thread = new Thread
就绪状态
调用start()方法,线程进入就绪状态,但并不意味着线程就立即执行,只是说明此线程已经做好准备,随时等待CPU调度执行。
阻塞状态
多个线程同时竞争一个独占锁,其他未抢到锁的线程,就进入阻塞状态被放置到锁池中,直到获取到锁,进入就绪状态
等待状态
该线程需要等待其他线程做出一些特定动作,通知或者是中断,等待其被其他线程唤醒,像CountDownLatch就可以等待一个或者几个线程结束。
超时等待状态
和等待状态不同的是,它可以在指定的时间自行的返回,sheep(long)函数就会让线程进入超时等待状态,时间到了才会转入就绪状态。
运行状态(Running)
CPU调度处于就绪状态的线程时,这个线程才真正执行,进入运行状态。
终止状态
线程正常执行完毕后或提前强制性终止或出现异常,线程就要销毁,释放资源。
线程的方法调用
获取线程基本信息
public class ThreadDemo6 {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run(){
/*获取线程唯一id标识*/
long id = this.getId();
System.out.println("thread的ID==>" + id);
/*获取线程名字*/
String name = this.getName();
System.out.println("thread的名字==>" + name);
/*获取线程的优先级 默认5 1-10*/
int priority = this.getPriority();
System.out.println("thread的优先等级==>" + priority);
/*查看当前线程是否为守护线程*/
boolean isDaemon = this.isDaemon();
System.out.println("thread是否为守护线程==>" + isDaemon);
/*查看线程是否被中断*/
boolean isInterrupted = this.isInterrupted();
System.out.println("thread是否被中断==>" + isInterrupted);
}
};
thread.start();
}
}
执行结果
thread的ID==>11
thread的名字==>Thread-0
thread的优先等级==>5
thread是否为守护线程==>false
thread是否被中断==>false
Thread.yield()
public class ThreadDemo1 implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public ThreadDemo1(){}
public ThreadDemo1(int countDown){
this.countDown = countDown;
}
public String status(){
return "#" + id + "(" + (countDown > 0 ? countDown : "stop!") + ")";
}
@Override
public void run() {
while (countDown-- > 0){
System.out.println(status() + " ");
Thread.yield();
}
}
public static void main(String[] args) {
for (int i = 0; i < 3; i++){
new Thread(new ThreadDemo1()).start();
}
}
}
#0(9)#0(8)#0(7)#0(6)#0(5)#0(4)#0(3)#0(2)#0(1)#0(stop!)
#1(9)#1(8)#1(7)#1(6)#1(5)#1(4)#1(3)#1(2)#1(1)#1(stop!)
#2(9)#2(8)#2(7)#2(6)#2(5)#2(4)#2(3)#2(2)#2(1)#2(stop!)
这个是一个倒计时的任务,对Thread.yield()调用是对线程调度器的一种建议,它在声明“我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机”,说白就是自己按暂停键,让出自己CPU的使用权限,转为就绪状态,至于下一次什么时候能获得CPU调度就不一定了,有时很快,有时得等上一会。
Thread.sleep
public class ThreadDemo1 implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public ThreadDemo1(){}
public ThreadDemo1(int countDown){
this.countDown = countDown;
}
public String status(){
return "#" + id + "(" + (countDown > 0 ? countDown : "stop!") + ")";
}
@Override
public void run() {
try {
while (countDown-- > 0){
System.out.println(status());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for (int i = 0; i < 3; i++){
new Thread(new ThreadDemo1()).start();
}
}
}

Thread.sleep(long)将使“正在执行的任务“中止执行给定的时间(暂停执行)并且让出CPU使用权,这个语句相当于说在接下来的1秒内,你都不要叫我,我想睡一会,1秒睡眠时间过后,它自动转为就绪状态,但CPU不一定马上执行这个睡醒的线程,这要取决于是否抢到CPU时间片段。值得注意的是如果sleep和yield上下文被加锁了,它们依然使用锁,不会去释放。而sleep与yield最大的不同是,yield不会让线程进入等待状态,只是把线程转为就绪状态,并把CPU执行机会让步给优先级相同或者更高的线程,而sleep能控制具体交出CPU的使用时间。
Thread.currentThread()
public class ThreadDemo2 extends Thread {
static {
System.out.println("静态块执行的线程===>" + Thread.currentThread().getName());
}
{
System.out.println("非静态块执行的线程是====>" + Thread.currentThread().getName());
System.out.println("this.getName()1=====>" + this.getName());
}
public ThreadDemo2(){
System.out.println("构造方法内执行的线程====>" + Thread.currentThread().getName());
System.out.println("this.getName()2=====>" + this.getName());
}
@Override
public void run() {
System.out.println("当前执行的线程为====>" + Thread.currentThread().getName());
System.out.println("this.getName()3=====>" + this.getName());
}
public static void main(String[] args) {
ThreadDemo2 threadDemo2 = new ThreadDemo2();
threadDemo2.start();
}
}
执行结果
静态块执行的线程===>main
非静态块执行的线程是====>main
this.getName()1=====>Thread-0
构造方法内执行的线程====>main
this.getName()2=====>Thread-0
当前执行的线程为====>Thread-0
this.getName()3=====>Thread-0
currentThread返回的是当前正在执行线程对象的引用,它与this.getName()有明显的不同,执行静态块,非静态块,构造方法的线程是main,而非ThreadDemo2,在执行run()方法的才是实例化的线程threadDemo2。所以在当前执行的Thread未必就是Thread本身。
isAlive()
public class ThreadDemo3 extends Thread {
@Override
public void run(){
System.out.println("执行执行====" + this.isAlive());
}
public static void main(String[] args) {
ThreadDemo3 threadDemo3 = new ThreadDemo3();
System.out.println("begin===>" + threadDemo3.isAlive());
threadDemo3.start();
System.out.println("end==>" + threadDemo3.isAlive());
}
}
begin===>false
end==>true
执行执行====true
isAlive()检测线程是否处于活动状态,活动状态返回true
setPriority()
优先级设定,优先级高的线程越容易获取CPU使用权,
public class ThreadDemo4 {
public static void main(String[] args) {
for (int i = 0; i < 5; ++i){
Thread1 thread1 = new Thread1();
thread1.setPriority(6);
Thread2 thread2 = new Thread2();
thread2.setPriority(4);
thread2.start();
thread1.start();
}
}
}
class Thread1 extends Thread{
@Override
public void run(){
for (int i = 0; i < 100000; ++i){
System.out.println("+++++++++++++");
}
}
}
class Thread2 extends Thread{
@Override
public void run(){
for (int i = 0; i < 100000; ++i){
System.out.println("--------------");
}
}
}
执行结果
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
...
CPU会将资源尽量让给优先级高的线程
setDaemon()
守护线程,也有人叫后天线程,我们创建出来的线程默认都是前台线程,在使用上来说,守护线程和前台线程是没啥区别,区别在于进程结束,当一个进程中的所有前台线程都结束时,无论这个进程中的守护线程是否还在运行都要强制将他们结束。也就是说前台线程都结束了,守护线程也会自动销毁,它是为其他线程提供便利而存在的。
/*rose与jack*/
public class ThreadDemo5 {
public static void main(String[] args) {
Rose rose = new Rose();
Jack jack = new Jack();
/*设置为守护线程必须在线程未启动之前*/
jack.setDaemon(true);
rose.start();
jack.start();
}
}
class Rose extends Thread{
@Override
public void run(){
for (int i = 0; i < 5; ++i){
System.out.println("rose: let me go!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("成功跳水");
}
}
class Jack extends Thread{
@Override
public void run(){
while (true){
System.out.println("jack:you jump! i jump!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
执行结果
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
成功跳水
jack守护着rose,jack是守护线程,当rose跳水后,jack认为自己也没有活着的必要了,也自己销毁了,但注意一点是这当中还有一个第三者main,需要main也运行完jack线程才会销毁。
join()
这个方法可以协调多个线程同步运行,多线程运行本身是设计异步运行的,但在程序运行业务中,有可能线程A的计算需要线程B的返回结果,这就需要他们执行各自任务时要有先后,join就需要协调这些线程同步运行。
public class ThreadDemo6 {
private static boolean isFinish = false;
public static void main(String[] args) {
Thread download = new Thread(){
@Override
public void run(){
System.out.println("下载图片中.....");
for (int i = 1; i <= 100; ++i){
System.out.println("下载进度" + i + "%");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("图片下载完毕");
isFinish = true;
}
};
Thread show = new Thread(){
@Override
public void run(){
System.out.println("开始显示图片...");
try {
download.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!isFinish){
throw new RuntimeException("图片下载出错");
}
System.out.println("图片正常展示。。。");
}
};
download.start();
show.start();
}
}
执行结果
下载图片中.....
开始显示图片...
下载进度1%
下载进度2%
...
下载进度100%
图片下载完毕
图片正常展示。。。
show调用join会使show无限阻塞,直到down线程销毁为止,它和sleep最大的区别是join会释放锁,而sleep不会。
涉及到jmm内存模型,线程安全等,后面在介绍
Java的多线程1:线程的使用的更多相关文章
- Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...
- Java 基础 多线程和线程池基础
一,多线程 1.1 多线程介绍 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是进程中的一个执行单元,负 ...
- Java:多线程,线程池,使用CompletionService通过Future来处理Callable的返回结果
1. 背景 在Java5的多线程中,可以使用Callable接口来实现具有返回值的线程.使用线程池的submit方法提交Callable任务,利用submit方法返回的Future存根,调用此存根的g ...
- java核心技术-多线程之线程内存模型
对于每一种编程语言,理解它的内存模型是理所当然的重要.下面我们从jvm的内存模型来体会下java(不限java语言,严格来讲是JVM内存模型,所有JVM体系的变成语言均适用)的内存模型. 堆: 就是我 ...
- java核心-多线程(4)-线程类基础知识
1.并发 <1>使用并发的一个重要原因是提高执行效率.由于I/O等情况阻塞,单个任务并不能充分利用CPU时间.所以在单处理器的机器上也应该使用并发. <2>为了实现并发,操作系 ...
- java核心技术-多线程之线程基础
说起线程,无法免俗首先要弄清楚的三个概念就是:进程.线程.协程.OK,那什么是进程,什么是线程,哪协程又是啥东西.进程:进程可以简单的理解为运行在操作系统中的程序,程序时静态代码,进程是动态运行着的代 ...
- Java:多线程,线程池,ThreadPoolExecutor详解
1. ThreadPoolExecutor的一个常用的构造方法 ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepA ...
- Java:多线程,线程池,用Executors静态工厂生成常用线程池
一: newSingleThreadExecutor 创建一个单线程的线程池,以无界队列方式运行.这个线程池只有一个线程在工作(如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它.)此线程池 ...
- Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...
- Java自学-多线程 常见线程方法
Java 常见的线程方法 示例 1 : 当前线程暂停 Thread.sleep(1000); 表示当前线程暂停1000毫秒 ,其他线程不受影响 Thread.sleep(1000); 会抛出Inter ...
随机推荐
- Adobe Premiere Pro 2020破解教程
首先官网下载Adobe Creative Cloud,安装完之后使用它继续安装Pr.注意在安装之前,点击文件→首选项,先设置一下你的安装路径,没有设置则默认安装在C盘. 接着下载网上良心博主推荐的破解 ...
- markdown简明语法1
目录 Cmd Markdown 简明语法手册 1. 斜体和粗体 2. 分级标题 3. 外链接 4. 无序列表 5. 有序列表 6. 文字引用 7. 行内代码块 8. 代码块 9. 插入图像 Cmd M ...
- seo搜索优化教程05-SEO常用专业术语
SEO常用的专业术语很多,星辉信息科技专门抽空进行了整理,主要如下:. SEO 根据搜索引擎规则来进行搜索引擎优化,进而使得在搜索结果中获得较好的排名 关键词 关键词也叫keywords,表示在搜索引 ...
- Python学习笔记.基础一
Python 语言:解释型.交互式.面向对象. Python源代码遵循GPL协议 Python标识符 在python里,标识符有字母.数字.下划线组成. 在python中,所有标识符可以包括英 ...
- Spring Boot从入门到精通(八)日志管理实现和配置信息分析
Spring Boot对日志的处理,与平时我们处理日志的方式完全一致,它为Java Util Logging.Log4J2和Logback提供了默认配置.对于每种日志都预先配置使用控制台输出和可选的文 ...
- (转)USB的VID和PID,以及分类(Class,SubClass,Protocol)
USB的VID和PID,以及分类(Class,SubClass,Protocol) 原文地址:http://blog.csdn.net/gaojinshan/article/details/78783 ...
- textareaCenter 未完结 其实就是iview的textarea的从写一遍 需求是光标上下居中
重点1: 一但赋值内容,光标会失去,导致光标到第一位 解决方法 设置一个状态位isChange,编辑的时候不进行watch更新,因为emit会自动改变外层的值,触发watch 解决方法2 找回上一次的 ...
- 使用WireShark进行网络流量安全分析
WireShark的过滤规则 伯克利包过滤(BPF)(应用在wireshark的捕获过滤器上) ** 伯克利包过滤中的限定符有下面的三种:** Type:这种限定符表示指代的对象,例如IP地址,子网或 ...
- DVWA Brute Force 解析
LOW 源代码如下: <?php if( isset( $_GET['Login'] ) ) { $user = $_GET['username']; $pass = $_GET['passwo ...
- angular 中嵌套 iframe 报错
错误如下 Error: unsafe value used in a resource URL context at DomSanitizationServiceImpl.sanitize... 解决 ...