【JAVA基础篇】多线程
学习Java的多线程知识之前,我们先来了解一下进程和线程的概念,以及他们之间的关系。
进程
基本概念
进程是具有独立功能的程序在某个数据集合上的一次执行过程。
特点
- 进程是操作系统进行资源分配和调度的基本单位。
- 每个进程都有自己的地址空间,即进程空间。
线程
基本概念
一个进程内部的一个执行单元,它是程序中的一个单一的顺序控制流程。
特点
- 自己不拥有系统资源,只拥有一点儿在运行过程中必不可少的资源。与同一个进程下的其他所有线程共享进程所拥有的全部资源。
- 线程是进程中的一个实体,是被系统独立调度和分派的基本单位。
进程和线程的联系和区别
进程是资源分配的基本单位,线程是调度的基本单位。进程包含线程,线程共用进程的资源。
Java实现多线程
有四种方式:
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口,并与FutureTask结合使用
- 线程池
继承Thread类
package com.cc.thread;public class ThreadDemo extends Thread{public ThreadDemo(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(this.getName()+i);}}public static void main(String[] args) {new ThreadDemo("张三").start();new ThreadDemo("李四").start();}}
实现Runnable接口
package com.cc.thread;public class RunableDemo implements Runnable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public RunableDemo(String name) {super();this.name = name;}@Overridepublic void run() {for (int i = 0; i < 10000; i++) {System.out.println(this.getName()+i);}}public static void main(String[] args) {new Thread(new RunableDemo("张三")).start();new Thread(new RunableDemo("李四")).start();}}
实现Callable接口,并与FutureTask结合使用
package com.cc.thread;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class CallableDemo {public static void main(String[] args) {CallableImpl callableImpl = new CallableImpl();FutureTask<Integer> futureTask = new FutureTask<Integer>(callableImpl);Thread thread = new Thread(futureTask);thread.start();try {int sum = futureTask.get();System.out.println(sum);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}private static class CallableImpl implements Callable<Integer>{@Overridepublic Integer call() throws Exception {int sum = 0;for (int j = 0; j <= 100; j++) {System.out.println(Thread.currentThread().getName()+":"+j);sum += j;}return sum;}}}
运行上面的代码,我们发现每次返回的结果都是5050(这么巧的吗?难道每次call方法瞬间就执行完了,然后再执行的int sum = futureTask.get();),其实如果线程的call方法还未执行完毕,futureTask.get()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。
线程的生命周期
通过查看Thread内部类State的源码,我们知道线程有6中状态,分别是:
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
Thread内部类State的源码
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;}
关于线程状态的详细描述和他们之前的相互转换请参考4 Java线程的状态及主要转化方法 · 深入浅出Java多线程
线程方法总结
start | 使线程由新建状态进入就绪状态,只能调用一次,否则会报IllegalThreadStateException |
run | 线程执行体,由系统调用 |
isAlive | 新建和死亡状态会返回false,其他状态返回true |
interrupt | 设置线程中断状态为true |
interrupted | static方法,先返回当前线程中断状态,然后设置线程中断状态为false |
isInterrupted | 返回当前线程中断状态 |
sleep | static native方法,使线程进入阻塞状态(不会释放同步锁) |
currentThread | static方法,该方法返回当前正在使用CPU资源的线程 |
setPriority |
final方法,设置线程的优先级,1~10 1最低 10最高 5是默认值 线程的优先级具有继承性,比如A线程启动B线程,则A和B的线程优先级是一样的 |
getPriority | final方法,获取线程优先级 |
setDaemon | 设置守护线程(也叫服务线程,用于为系统中的对象和线程提供服务,如果都是服务线程,那么JVM结束,垃圾回收线程是守护线程) |
isDaemon | 判断是否是守护线程 |
join | thread1.join();使当前线程进入阻塞状态,thread1线程执行完后,再唤醒当前线程 |
yeild | 使当前线程进入就绪状态 |
wait | Object类的方法,让当前线程进入阻塞状态,并且释放它持有的同步锁 |
notify | Object类的方法,唤醒一个阻塞状态的线程 |
notifyAll | Object类的方法,唤醒所有阻塞状态的线程 |
join方法的使用
package com.cc.thread;public class ThreadJoin {public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread("线程1"){@Overridepublic void run() {for (int i = 0; i < 1000; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}};thread1.start();thread1.join();for (int i = 0; i < 100; i++) {System.out.println(Thread.currentThread().getName()+":"+i);}}}
interrupt、interrupted和isInterrupted的作用和区别
- interrupt设置线程中断状态为true
- interrupted先返回当前线程中断状态,然后设置线程中断状态为false
- isInterrupted返回当前线程中断状态
- 下面的demo只用到了sleep方法,wait,join方法类似于sleep
package com.cc.thread;public class InterruptTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(){@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {sleep(2000);//线程默认中断状态为false,调用sleep方法,或者在sleep的过程中,当中断状态为true时,执行sleep会抛出异常interrupt();//设置中断状态为true} catch (InterruptedException e) {//抛出异常后中断状态自动设置为falseSystem.out.println("出现中断异常,中断状态:"+isInterrupted());}System.out.println("正常执行,中断状态:"+isInterrupted());}}};thread.start();}}
package com.cc.thread;public class InterruptTest {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(){@Overridepublic void run() {for (int i = 0; i < 5; i++) {try {sleep(2000);//线程默认中断状态为false,调用sleep方法,或者在sleep的过程中,当中断状态为true时,执行sleep会抛出异常interrupt();//设置中断状态为trueSystem.out.println("interrupted方法:"+interrupted());//此函数首先返回当前的中断状态,然后将中断状态置为falseSystem.out.println("isInterrupted:"+isInterrupted());} catch (InterruptedException e) {//抛出异常后中断状态自动设置为falseSystem.out.println("出现中断异常,中断状态:"+isInterrupted());}System.out.println("正常执行,中断状态:"+isInterrupted());}}};thread.start();}}
wait方法的使用
package com.cc.thread;public class ObjectWait {public static void main(String[] args) {try {Thread threadTest = new Thread(){public void run(){System.out.println("执行线程中方法");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}};threadTest.start();synchronized(threadTest){threadTest.wait(); //当线程终止的时候,会调用线程自身的notifyAll()方法}System.out.println("执行到了这里");} catch (InterruptedException e) {e.printStackTrace();}}
}
synchronized
synchronized的用法参考Java中使用同步关键字synchronized需要注意的问题 - @ 小浩 - 博客园
synchronized是非公平锁
synchronized的实现原理参考Java中的锁——Lock和synchronized - 夏末秋涼 - 博客园
1,synchronized代码块基于进入和退出monitor对象实现。代码编译后将monitorenter指令插入同步代码块的前面,monitorexit指令插入同步代码块的后面,发生异常时也会执行monitorexit指令
2,synchronized方法读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的
3,synchronized用的锁存储在对象头中的markword,markword中的锁标记指向的是monitor对象,
锁标记位(无锁01、轻量级锁00、重量级锁10、偏向锁01)
4,monitor对象有两个队列(EntryList、WaitSet)以及锁持有者Owner标记
线程安全的概念
什么是线程安全:在多线程环境下,线程安全的代码会通过线程同步机制保证各个线程可以正常的正确的执行,不会出现数据污染等意外情况。
什么是线程同步:是指各个线程按照一定的顺序执行
【JAVA基础篇】多线程相关推荐
- Java基础篇--多线程之第一个线程用来计算2~100000之间的素数的个数,第二个线程用来计算100000~200000之间的素数的个数
多线程操作: 编写一个有两个线程的程序,第一个线程用来计算2-100000之间的素数的个数,第二个线程用来计算100000-200000之间的素数的个数,最后输出结果. 1.判断是否为素数的方法: 是 ...
- 《Java 后端面试经》Java 基础篇
<Java 后端面试经>专栏文章索引: <Java 后端面试经>Java 基础篇 <Java 后端面试经>Java EE 篇 <Java 后端面试经>数 ...
- 【程序员养成之路】Java基础篇 8-流进流出的IO流(二)
以下内容若有误,欢迎私信我或在下方留言,谢谢^_− 目录 IO流(二) 1.特殊操作流 1.1 标准流 1.2 打印流 1.3 对象序列化流 1.4 Properties 拓展1:比较字节流和字节缓冲 ...
- Java 基础篇(一)基本概念
Java 基础篇系列文章目录 Java 基础篇(一)基本概念 Java 基础篇(二)数据类型 Java 基础篇(三)控制逻辑 文章目录 Java 基础篇系列文章目录 Java(软件开发) Java(编 ...
- Java基础篇 学习笔记
List item Java基础篇 学习笔记 java基础篇 第1章 计算机.程序和java概述 学习笔记 1.1什么是计算机 简单来说:计算机就是 ' 存储 ' 和 ' 处理 ' 数据的电子设备. ...
- 高频面试真题答案 -java后端 -java基础篇
原贴 2022届秋招高频面试真题汇总,千题奉送!!!- 后端篇_笔经面经_牛客网 整理答案: 类加载机制 47 双亲委派机制 24 new一个对象的过程 4 java程序是如何运行起来的? 1 jvm ...
- Java基础、多线程、JVM、集合八股文自述(持续更新)
Java基础.多线程.JVM.集合八股文自述 一.Java基础 1.1 object类有哪些方法? getClass().hashCode().equals().clone().toString(). ...
- 你所需要的java基础篇深入解析大汇总
java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...
- Java基础篇4——数组
Java基础篇4--数组 1.数组的概念 当需要在Java程序中记录单个数据内容时,则声明一个变量即可 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数 组即可,一维数组本质上就是 ...
- Java基础篇3——流程控制
Java基础篇3--流程控制 1.顺序结构 正常代码的流程即是顺序流程 2.分支结构 2.1.if-else分支 if(条件表达式) {语句块1; } if(条件表达式) {语句块1; } else ...
最新文章
- 多个video标签,控制最多只能一个同时播放
- flutter 几秒前, 几分钟前, 几小时前, 几天前...
- 为什么用链路聚合_H3C ComwareV7平台网络设备可靠性配置——链路聚合
- 架构设计:负载均衡层设计方案(3)——Nginx进阶
- Oracle全备增量备份脚本,ORACLE-RMAN:备份脚本(全库,增量)
- 数据集中异常值的处理之lof,iforest算法
- 【枚举排列】生成1~n的排列生成可重集的排列
- Java从json串中获取某个值
- 阿里Java开发手册(2021最新终极版) 编程必备
- 图像处理——插值算法
- SRP Batcher:提升您的渲染性能
- ictclas java 下载,10分钟开始使用ICTCLAS Java版
- 用hidusb.sys还是winusb.sys读写一个只有In/Out Interrupt Endpoints的STM32 USB设备?
- 找出列表中重复数的下标
- 用c语言实现1+2+3+...+n求和
- 带你掌握Visual Studio Code的格式化程序
- http协议的状态码 200、301、304、404、502 HTTP状态码解释
- 绝对的开怀大笑-轻松一下
- 推荐一个Linux远程桌面工具
- 为什么选择.NETCore
热门文章
- 防saq注入_去中心化交易所CYBEX将为区块链ICO注入新的价值观
- apache 统计404日志_Apache监控与调优(四)Apachetop监控
- Oracle run leve,UNIX自动启动oracle
- 服务器漏洞处理_wildfly禁用https和8443端口
- Vue 实现 Open Graph 分享预览
- php数组 函数,PHP array_uintersect_uassoc() 函数
- C语言 const 修饰指针 - C语言零基础入门教程
- Python type 函数- Python零基础入门教程
- jq之mouseleave()
- ajax中res和req,javascript – 来自AJAX调用的res.redirect