Java 并发(入门梳理)
>多线程创建方式
继承一个类 Thread
或者实现一个接口 Runnable
重写其中的 run() 方法(对于实现接口的形式,并没有继承run() 方法,要通过构造扔到一个Thread对象中去运行)
使用 start() 方法
>原子性操作
多线程环境下,如果一个操作不是原子性操作,那么需要考虑它的安全性。
什么是原子性操作?
不可分割的操作
++i;是不是原子性操作?
不是,在 jvm 中分为三步:取出 i 的值;让 i 的值加一; 将自加后的值赋给 i 。
>举个例子,四个线程,每个线程加一万次
public class ReTh {int i = 0;//加锁,因为 i 是非原子性操作,可能第一线程自加未赋值,后续线程又进行了操作public synchronized void add() {++i;}public static void main(String[] args) {ReTh rt = new ReTh();for (int i = 0; i < 4; i++) {new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {rt.add();}}}).start();}while (Thread.activeCount() > 1) {//等待,并发就是多个分支一并往下走,如果这里不等待,主线程就在四个线程没加完//的时刻就进行了打印 i,得不到40000}System.out.println(rt.i);//40000}}
>线程控制
首先要明确,并发的线程,抢占式运行。
三种线程控制:
join() 加塞:
一个线程过来,有"急事",让他独立占用cpu,等它执行完了,我再执行,我们并不是并行关系。
sleep() 睡眠 :
让当前线程睡眠多久。当前线程醒来的时候,是重新竞争CPU,还是?
当这个线程"睡觉"的时候,是抱着cpu"睡觉",醒来的时候直接获得执行权力。
yield() 让步/放弃:
当一个线程获得cpu执行权力,调用yield,放弃执行权力,退一步,大家再重新抢。
>线程的生命周期
新建:当我们创建了线程对象的时候。
就绪:当我们调用了线程的 start 方法之后。
运行:当获取了cpu的时候。
阻塞:单说。
死亡:运行完。或者运行的时候抛出异常。
>阻塞
线程进入阻塞状态的情况:
- 线程调用了一个阻塞方法,方法返回之前该线程一直阻塞。
- 线程调用 sleep() 方法进入阻塞。
- 线程尝试获取 同步监视器 ,但该同步监视器被其他线程持有。
- 线程调用 suspend() 方法挂起。
>线程优先级(不可靠,不要依赖优先级控制线程)
new Thread().setPriority(Thread.MAX_PRIORITY);
>线程安全(重点)
多个线程操作的同一个类的同一个对象时,会存在线程安全问题。
解决:同步代码块/同步方法
public class TestSafe {V v = new V();public void go() {new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}v.printString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");}}}).start();new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}v.printString("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");}}}).start();}class V {public synchronized void printString(String s) {/*** 假设这里有大量业务代码,如何降低 锁 的粒度?*/synchronized (String.class) {}for (int i = 0; i < s.length(); i++) {System.out.print(s.charAt(i));}System.out.println();/*** 假设这里有大量业务代码*/}}public static void main(String[] args) {TestSafe t = new TestSafe();t.go();}}
>wait / notify,notifyAll(重点)
1.首先明确一点,这三个方法不是Thread类的方法,是Object类的native方法。
2.要调用这些方法,必须获得同步监视器(锁),否则会报异常(换句话说我们线程在调用这些方法的地方,要有synchronized关键字,这样执行,就会获取锁)。
补充:
1)静态方法上的锁
静态方法是属于“类”,不属于某个实例,是所有对象实例所共享的方法。也就是说如果在静态方法上加入synchronized,那么它获取的就是这个类的锁,锁住的就是这个类。
2)实例方法(普通方法)上的锁,锁住的就是这个对象实例,synchronized(this){}也是锁的对象。
3.wait 的意思:等待时机成熟再执行,否则就等待。
再执行的时候,必须被别的线程唤醒,它自己醒不了。
4.notify/notifyAll ,专门唤醒等待队列中的线程(随机唤醒某一个/唤醒所有的),唤醒之后再判断条件是否满足。
>轮询执行的问题
这种问题的思路:同一时刻只能让一个线程在运行,其他线程wait() 等待唤醒,如果同一时刻多个线程抢占CPU就失去了控制;线程的运行和唤醒要通过额外的 条件/flag 进行轮询的控制。
写一个程序,让两个线程轮询执行 ?
public class TestWaitNotify {public static void main(String[] args) {TestWaitNotify t = new TestWaitNotify();t.go();}V v = new V();private void go() {new Thread(new Runnable() {@Overridepublic void run() {while (true) {v.f1();}}}, "A线程").start();new Thread(new Runnable() {@Overridepublic void run() {while (true) {v.f2();}}}, "B线程").start();}class V {public boolean flag=true;public synchronized void f1() {while(flag){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("F1 " + Thread.currentThread().getName());flag=true;notifyAll();}public synchronized void f2() {while(!flag){try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("F2 " + Thread.currentThread().getName());flag=false;notifyAll();}}
}
三个线程轮询执行?
public class ThreeThreadInTurn {public static void main(String[] args) {ThreeThreadInTurn t = new ThreeThreadInTurn();t.go();}V v = new V();public void go() {new Thread(new Runnable() {@Overridepublic void run() {while (true) {v.f1();}}}, "线程1").start();new Thread(new Runnable() {@Overridepublic void run() {while (true) {v.f2();}}}, "线程2").start();new Thread(new Runnable() {@Overridepublic void run() {while (true) {v.f3();}}}, "线程3").start();}class V {int flag = 1;public synchronized void f1() {while (flag != 1) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("F1 " + Thread.currentThread().getName());flag = 2;notifyAll();}public synchronized void f2() {while (flag != 2) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("F1 " + Thread.currentThread().getName());flag = 3;notifyAll();}public synchronized void f3() {while (flag != 3) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("F1 " + Thread.currentThread().getName());flag = 1;notifyAll();}}}
Java 并发(入门梳理)相关推荐
- Java并发知识梳理(上):并发优缺点,线程状态转换,Java内存模型,Synchronized,Volatile,final,并发三特性,Lock与AQS,ReetrandLock
努力的意义,就是,在以后的日子里,放眼望去全是自己喜欢的人和事! 整个系列文章为Java并发专题,一是自己的兴趣,二是,这部分在实际理解上很有难度,另外在面试过程中也是经常被问到.所以在学习过程中,记 ...
- 《Java并发编程入门与高并发面试》or 《Java并发编程与高并发解决方案》笔记
<Java并发编程入门与高并发面试>or <Java并发编程与高并发解决方案>笔记 参考文章: (1)<Java并发编程入门与高并发面试>or <Java并发 ...
- Java高并发入门-线程初步(二)
Java高并发入门详细讲解 上期回顾及问题总结 上次说了创建线程的两种常用方式,第三种方式在后面的更新中会讲解到.这里对于上一节的内容做个回顾. 在上一节中说到了创建多线程的问题,分析了Thread的 ...
- Java高并发入门-线程初步
Java高并发入门-线程初步 线程与进程之间的关系 进程就是我们运行在计算机上的一个程序,对应Java程序来说就是运行在计算机上的Java应用程序,这个程序在运行的时候就会创建了一个进程,服务器上就会 ...
- 学习笔记:Java 并发编程①_基础知识入门
若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 视频下载: ...
- Java并发编程(中下篇)从入门到深入 超详细笔记
接上一篇博客笔记:Java并发编程(中上篇)从入门到深入 超详细笔记_未来很长,别只看眼前的博客-CSDN博客https://blog.csdn.net/weixin_53142722/article ...
- java并发编程入门_探讨一下!Java并发编程基础篇一
Java并发编程想必大家都不陌生,它是实现高并发/高流量的基础,今天我们就来一起学习这方面的内容. 什么是线程?什么是进程?他们之间有什么联系? 简单来说,进程就是程序的一次执行过程,它是系统进行资源 ...
- 2021全新Java多线程并发入门到精通,一篇就能学会
目录 一, JAVA 多线程并发 1,JAVA 并发知识库 2,JAVA 线程实现/创建方式 (1) 继承 Thread 类 (2)实现 Runnable 接口. (3)ExecutorService ...
- Java并发技术要点梳理
写在前面: Java并发这块内容无论是在工作中还是面试中都是常见而且实用的重点,推荐将本文一些关键代码自己运行一遍,以查看实际效果,这里推荐一个在线运行Java代码的网站 基本概念 名词解释 CPU线 ...
- Java 并发编程入门
JUC 写在前面 推荐阅读 http://ifeve.com/java-memory-model-1/ :深入理解 Java 内存模型-程晓明 https://segmentfault.com/a/1 ...
最新文章
- 职场中怎样评估系统架构师的成绩?
- Android开发之LisitView的图文并排效果实现(源代码分享)
- appserv 安装后phpmyadmin 密码问题 win7
- (一)SpringBoot 整合 MyBatis
- CockroachDB学习笔记——[译]在CockroachDB中如何让在线模式更改成为可能
- 啊哈算法-游戏币问题(dp)
- Intel开发工具之VTune
- 【Oracle】lsnrctl reload 命令简介
- 在网页中加入神奇的效果
- G-Sensor 校准标准
- android view强制重绘_安卓自定义 view 不能正常重绘
- c++ 栈 STL的基本操作
- 播布客全部视频教程汇总
- js高级--jsonp跨域
- 解决winform中的panel重绘闪烁问题
- Android studio:select process to attach to...找不到debug调试的目录
- 伦敦金走势图与顾比均线
- win10OneNote登录微软 账号登陆出现错误码0x80190001
- git runner 配置_GitLab Runner 入门及常见问题
- 陪伴我成长的学习工作邮箱品牌——TOM邮箱