一、Java多线程基础
一、简介
1、操作系统
在早起的裸机时代,计算机非常地昂贵,而且也没有操作系统的概念,计算机从头到尾只能执行一个程序。如果程序在执行一个耗时的操作,那么在这个过程中,计算机就有大量的资源闲置在那里,这是非常浪费的。
而这个时候,操作系统的概念被提出了。在操作系统的控制下,一个计算机可以执行很多的程序。计算机的资源由操作系统进行分配,程序之间获得计算机资源并执行各自的任务,相互独立。操作系统的出现使得计算机资源的利用率大大增加。
你也可以将操作系统理解为,运行程序的程序。类比AI是一种产生算法的算法。
2、进程和线程
操作系统可以执行多个程序,每个程序在计算机中即是一个“进程”。进程的执行是并行的,实际上这里的“并行”并不完全是物理意义上的并行。操作系统会给每个进程分配一定的执行时间,并且CPU在这些进程之间快速地切换执行,从而近似地达到了一种并行执行的效果。当然,现代CPU也从早期的单核发展为4核、8核,可以从物理上同时执行。即使是单核,也能够控制多个执行流达到物理上并发的目的。
操作系统使得程序得以并发执行,但随着需求的增加,我们希望每个程序也能够并发多个任务。所以,线程的概念就应运而生了。线程是依赖于进程的,共享进程的计算机资源。一个进程可以拥有一到多个线程。线程的并行执行和进程的理念是一样的,共享进程的时间片,快速地执行切换。
3、Java多线程
Java编程语言为帮助开发者开发多线程的应用程序设计了一套简单的语义,你可以利用Java的内置支持来构建多线程程序,充分利用CPU资源,提高程序的响应速度。
二、Java线程的生命周期
下图,摘录自菜鸟教程:http://www.runoob.com/java/java-multithreading.html

这个图相信大家都很熟悉,它是表达了线程的生命周期,包含了几个状态,如下:
1)创建:当我们在程序中new出来一个线程实例对象的时候,线程便处于创建状态;
2)就绪:当我们调用了start()方法,表示该线程即将等待JVM的native方法去调用我们的线程,也就是就绪状态;
3)运行:如果JVM调用了我们的线程,线程实例执行中,它就处于运行状态;
4)阻塞:运行过程中可能出现sleep、wait或者其它IO操作等,这个时候当前的线程就处于阻塞状态,让出CPU的资源,而不是继续占用。
5)死亡:如果线程正常执行完毕,手动退出或者意外结束,那么线程就进入了死亡状态,该线程占用的资源也会被自动回收。
三、使用示例
Java显示创建线程有两种实现:
1)继承Thread类
public class ThreadDemo extends Thread {
@Override
public void run() {
System.out.println("执行了" + Thread.currentThread().getName());
}
public static void main(String[] args) {
new ThreadDemo().start();
System.out.println("主线程执行了" + Thread.currentThread().getName());
}
}
事实上,Thread类实现了Runnable接口,而我们重写了Runnable的run方法,当调用start()方法的时候,该线程会调用native方法,从而JVM会去异步执行线程实例的run方法。
2)实现了Runnable接口
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("线程执行" + Thread.currentThread().getName());
}
public static void main(String[] args) {
new Thread(new RunnableDemo()).start();
System.out.println("主线程执行" + Thread.currentThread().getName());
}
}
实现Runnable接口的方式,也需要将Runnable作为Thread实例的构造入参,然后通过start()将线程转换为就绪状态。如果你直接调用run方法是不会异步运行的。
以上两种实现,其实都是基于Runnable接口和Thread类,只是写法不同。
四、常用API
- currentThread():静态方法,返回当前线程的引用
- getId():返回当前线程的标识符
- getName():返回当前线程的引用
- getPriority():返回当前线程的优先级
- getState():返回当前线程的状态
- interrupt():中断线程(仅是打上中断标识,无法强制停止线程)
- interrupted():静态方法,返回是否中断
- isAlive():是否存活
- isDaemon():是否守护线程
- isInterrupted():是否中断
- yield():静态方法,暂停当前线程,执行其它线程
- start():使线程进入就绪状态
- sleep(long millis):静态方法,使线程休眠
- setPriority(int priority):设置优先级,优先级高的会先执行
- setName():设置名字
- setDaemon():设置为守护线程
- join():等待其它线程中止以后再继续执行
- wait():等待notify唤醒
- notify():唤醒wait线程
yield示例
yield执行的时候暂停当前线程执行,让出CPU资源,去执行其它线程
public class YieldDemo {
private static volatile boolean isReady = false;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "让主线程执行");
while (!isReady) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "执行完毕");
}).start();
Thread.sleep(5000);
isReady = true;
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
join示例
join的作用是让将某个线程插入到当前线程的执行位置,并等待该线程执行完毕以后再执行当前线程。
public class JoinDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "开始执行");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "执行完毕");
});
thread.start();
System.out.println(Thread.currentThread().getName() + "等待子线程执行完毕");
thread.join();
System.out.println(Thread.currentThread().getName() + "执行完毕");
}
}
notify/wait示例
notify和wait使用比较特殊,需要获得同步锁资源
notify和wait方法是Object对象的方法,任何对象都会有。它的作用是什么呢?我们举一个场景示例:
1)存在两个线程A和B;
2)我们希望A执行完毕以后通知B去执行,而B在A通知之前一直等待
代码示例如下:
public class WaitDemo {
private static Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 3; i++) {
new Thread(() -> {
// 要先获得同步锁
synchronized (lock) {
try {
System.out.println(Thread.currentThread().getName() + " waiting");
// 等待notify
lock.wait();
System.out.println(Thread.currentThread().getName() + " end waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
System.out.println("sleep");
Thread.sleep(5000);
// 要先获得同步锁
synchronized (lock) {
System.out.println("notify");
// 执行notify
lock.notifyAll();
System.out.println("finished");
}
}
}
这里随意建立了一个lock对象作为锁对象,子线程拿到这个锁以后执行等待。而主线程拿到锁以后,发送通知,执行结果如下:
sleep
Thread-0 waiting
Thread-1 waiting
Thread-2 waiting
notify
finished
Thread-2 end waiting
Thread-1 end waiting
Thread-0 end waiting
注意:如果notifyAll()在wait()之前执行了,那么子线程将无线等待下去,你可以给wait设置超时时间
更多API示例,参考JDK文档:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/Thread.html
一、Java多线程基础的更多相关文章
- [转]Java多线程干货系列—(一)Java多线程基础
Java多线程干货系列—(一)Java多线程基础 字数7618 阅读1875 评论21 喜欢86 前言 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域,所以学好多线程并发编程对我们 ...
- Java多线程基础:进程和线程之由来
转载: Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够 ...
- Java 多线程——基础知识
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程--基础概念
Java多线程--基础概念 必须知道的几个概念 同步和异步 同步方法一旦开始,调用者必须等到方法调用返回后,才能执行后续行为:而异步方法调用,一旦开始,方法调用就立即返回,调用者不用等待就可以继续执行 ...
- Java多线程基础知识总结
2016-07-18 15:40:51 Java 多线程基础 1. 线程和进程 1.1 进程的概念 进程是表示资源分配的基本单位,又是调度运行的基本单位.例如,用户运行自己的程序,系统就创建一个进程, ...
- Java基础16:Java多线程基础最全总结
Java基础16:Java多线程基础最全总结 Java中的线程 Java之父对线程的定义是: 线程是一个独立执行的调用序列,同一个进程的线程在同一时刻共享一些系统资源(比如文件句柄等)也能访问同一个进 ...
- 1、Java多线程基础:进程和线程之由来
Java多线程基础:进程和线程之由来 在前面,已经介绍了Java的基础知识,现在我们来讨论一点稍微难一点的问题:Java并发编程.当然,Java并发编程涉及到很多方面的内容,不是一朝一夕就能够融会贯通 ...
- Java 多线程基础(一)基本概念
Java 多线程基础(一)基本概念 一.并发与并行 1.并发:指两个或多个事件在同一个时间段内发生. 2.并行:指两个或多个事件在同一时刻发生(同时发生). 在操作系统中,安装了多个程序,并发指的是在 ...
- Java 多线程基础(三) start() 和 run()
Java 多线程基础(三) start() 和 run() 通过之前的学习可以看到,创建多线程过程中,最常用的便是 Thread 类中的 start() 方法和线程类的 run() 方法.两个方法都包 ...
- Java 多线程基础(四)线程安全
Java 多线程基础(四)线程安全 在多线程环境下,如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线 ...
随机推荐
- 视频video遇到一些坑
1.video层级最高问题 解决方案思路:当点击其他按钮触发事件时,视频层级挡住其他外层,比如会挡住弹窗,这是应该让视频暂停播放且隐藏,这是视频这个地方会空一个位置可以放一张封面占位,这样就解决视频层 ...
- 【文文殿下】 [SDOI2016]生成魔咒
字符集大小为1e9.............使用 map 吧 统计本质不同的子串个数是SAM的经典应用之一 本质不同的子串个数其实就是\(\sum max(x)-min(x)+1\) 所以我们新建结点 ...
- 面向对象之-@classmethod、@staticmethod和@classonlymethod的区别
实例方法.静态方法与类方法的含义 实例方法(普通方法)的含义就是需要类对象实例之后才能调用的方法,该方法的基本格式为: def test(self,*args,**kwargs): # 第一个参数必须 ...
- grunt 常用插件
grunt-contrib-uglify:代码压缩 grunt-contrib-jshint:检查js拼写错误 csslint:检查css语法错误
- Linux 中使用 virsh 管理 KVM 虚拟机 (转)
术语 虚拟化指的是:在相同的物理(硬件)系统上,同时运行多个操作系统,且这几个系统相互隔离的可能性,而那个硬件在虚拟化架构中被称作宿主机(host).虚拟机监视器(也被称为虚拟机管理程序(hyperv ...
- SpringBoot idea maven打包war及运行war包
pom.xml修改打包类型pom改为war <artifactId>Test02</artifactId> <packaging>war</packaging ...
- Java中类变量和实例变量的初始化
1. 类变量和实例变量 类变量即类成员变量中的静态变量,它们可以通过类名来直接访问. 实例变量是类成员变量中的非静态变量,只有在实例化对象之后通过对象来访问. 2. 空间分配的时间不同 类变量是在类加 ...
- day 10 课后作业
# -*- coding: utf-8 -*-# @Time : 2019/1/2 16:35# @Author : Endless-cloud# @Site : # @File : 课后作业.py# ...
- CSS--浮动(float)布局
浮动概述:浮动,指的是元素标签使用float属性.应用float属性的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止.浮动的本质是让文字围绕图片,但现在很多时候使用浮动进行布局 ...
- 集合之五:Set接口(答案)
package com.shsxt.homework; import java.util.ArrayList; import java.util.Collection; import java.uti ...