Java 高级 多线程 线程安全 3 种常见解决方案教程.
我们在访问多线程的共有变量的时候容易出现线程安全问题详见线程安全问题产生的原理分析
一、方案1.同步代码块.
1.原理:把同步代码块锁住,只允许一个线程在同步代码块中执行。
2.图解:
3.使用格式
synchronized(锁对象呢){
可能出现线程安全问题的代码.}
4.代码目的:
模拟买票产生的线程安全问题。* 1.一个 Runnable 接口 创建3 个线程,new Thread(myRunnable)* 2.三个线程的start()抢占资源,导致 tickets 异常
5.注意事项
* 2.注意:
* 2,1:锁对象可以为任何对象,比如Object
* 2.2 :但是要保证多线程的锁对象为同一个
* 2.3:锁对象的作用:
* 2,3,1:把同步代码块锁住,只允许一个线程在同步代码块中执行。
* 3.出现的问题:注释掉之前的没有安全的线程,不然会混淆。
6.代码
Main.java
package Java学习.Java高级.多线程.线程安全问题.线程安全问题解决.解决1同步代码块;/*** 模拟买票产生的线程安全问题。* 1.一个 Runnable 接口 创建3 个线程,new Thread(myRunnable)* 2.三个线程的start()抢占资源,导致 tickets 异常* 二、线程安全问题的解决:* 1.格式* synchronized(锁对象呢){* 可能出现线程安全问题的代码.* }* 2.注意:* 2,1:锁对象可以为任何对象,比如Object* 2.2 :但是要保证多线程的锁对象为同一个* 2.3:锁对象的作用:* 2,3,1:把同步代码块锁住,只允许一个线程在同步代码块中执行。* 3.出现的问题:注释掉之前的没有安全的线程,不然会混淆。*/
public class Main {private int tickets = 100;public static void main(String[] args) {// MyRunnable myRunnable = new MyRunnable();
// Thread thread = new Thread(myRunnable);
// Thread thread1 = new Thread(myRunnable);
// Thread thread2 = new Thread(myRunnable);
// thread.start();
// thread1.start();
// thread2.start();System.out.println("==========使用同步代码块后=======");MyRunnable2 myRunnable2 = new MyRunnable2();Thread thread3 = new Thread(myRunnable2);Thread thread4 = new Thread(myRunnable2);Thread thread5 = new Thread(myRunnable2);thread3.start();thread4.start();thread5.start();}
}
MyRunnable.java
package Java学习.Java高级.多线程.线程安全问题.线程安全问题解决.解决1同步代码块;/*** 一、同步代码块线程安全的原理* 1. 同步代码块的线程没有锁对象不能执行(阻塞),* 2.正在执行的同步代码块会拿走锁对象,直到执行完才归还。* 二、详解:* 1. 执行线程:* 3个线程抢CPU执行权,比如 thread1 抢到了, thread1执行run方法,* 2.判断是否有锁对象lock:* 遇到synchronized(lock),检查是否有锁对象,有就拿走锁对象lock* 没有就阻塞,比如thread1拿到了锁对象开始执行* 3,thread2 执行线程:* thread2 抢到了cpu的执行权,run()方法,* 4.判断有没有锁对象:* thread2 的没有锁对象,(thread1拿走了正在运行还没归还)停止运行,阻塞*/
public class MyRunnable2 implements Runnable {private int tickets = 100;Object lock = new Object();@Overridepublic void run() {while (true) {synchronized (lock) {//必须把判断语句if写到同步代码块里,不然会出问题//判断也是会出线程安全的部分。if (tickets > 0) {System.out.println(tickets + "on selling...end");tickets--;try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}}}}}
}
sout:
100on selling…end
99on selling…end
98on selling…end
97on selling…end
96on selling…end
95on selling…end
94on selling…end
…
2on selling…end
1on selling…end
Ps:里面为了图方便写了一个死循环,建议输出完后关闭程序
二、同步方法.
1.原理,同步方法的原理和同步代码块一致.
* 三、为什么同步代码块和同步方法原理一致??,1,2 是等价的。* 1. 同步方法的锁对象是this,* private synchronized void synchronizedMethod(){* if (tickets > 0){* System.out.println(tickets + " on selling 。。。end.");* tickets --;* }* }*2. 同步方法的锁对象是this,* private void synchronizedMethod(){* synchronized(this){* if (tickets > 0){* System.out.println(tickets + " on selling 。。。end.");* tickets --;* }* }* }
2.步骤:
* 二、实现步骤:
* 1.在MyRunnable实现implements Runnable 的类里新建一个 synchronized 修饰的方法:
* private synchronized void synchronizedMethod(){* }
* 2. 把解决方法1 中,线程安全的代码(访问共有变量的代码)用方法调用代替即可
3.具体代码
Main.java
package Java学习.Java高级.多线程.线程安全问题.线程安全问题解决.解决2同步方法;/**
* 一、同步方法的原理和解决1的同步代码块一致
* 二、实现步骤:
* 1.在MyRunnable实现implements Runnable 的类里新建一个 synchronized 修饰的方法:
* private synchronized void synchronizedMethod(){
* }
* 2. 把解决方法1 中,线程安全的代码(访问共有变量的代码)用方法调用代替即可
* 三、为什么同步代码块和同步方法原理一致,1,2 3是等价的。
* 1. 同步方法的锁对象是this,
* private synchronized void synchronizedMethod(){
* if (tickets > 0){
* System.out.println(tickets + " on selling 。。。end.");
* tickets --;
* }
* }
* 2. 同步方法的锁对象是this,
* private void synchronizedMethod(){
* synchronized(this){
* if (tickets > 0){
* System.out.println(tickets + " on selling 。。。end.");
* tickets --;
* }
* }
* }
* 3. 解决1.
*/
public class Main {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread1 = new Thread(myRunnable);Thread thread2 = new Thread(myRunnable);Thread thread3 = new Thread(myRunnable);thread1.start();thread2.start();thread3.start();}
}
MyRunnable.java
package Java学习.Java高级.多线程.线程安全问题.线程安全问题解决.解决2同步方法;public class MyRunnable implements Runnable {private int tickets = 100;@Overridepublic void run() {while (true){//把有线程安全问题(访问共有变量池)的代码用同步方法解决synchronizedMethod();}}private synchronized void synchronizedMethod(){if (tickets > 0){System.out.println(tickets + " on selling 。。。end.");tickets --;}}
}
sout:
100 on selling 。。。end.
99 on selling 。。。end.
98 on selling 。。。end.
97 on selling 。。。end.
96 on selling 。。。end.
95 on selling 。。。end.
94 on selling 。。。end.
…
2 on selling 。。。end.
1 on selling 。。。end.
ps:笔者因为图便利写了死循环,请输出完后关闭程序
三、Lock接口.
* 一、更高级的lock接口:* 1.常用方法:* 1,1 void lock()加锁* 1.2 void unlock()解锁* 2.常用的接口的实现类:* 1. ReentrantLock implements Lock;* 二、具体使用步骤:* 1,在成员位置创建ReentrantLock对象(多态)* Lock lock = new ReentrantLock();* 2. 在线程安全的问题代码(访问共有变量的代码块)前后加上获取锁和释放锁。* 四、代码优化:* 1.把锁的释放放到finally语句里,无论线程语句是否异常都会开锁,不会影响其他代码是运行。
1.代码
Mian.java
package Java学习.Java高级.多线程.线程安全问题.线程安全问题解决.解决3更高级的Lock接口;/**
* 一、更高级的lock接口:
* 1.常用方法:
* 1,1 void lock()加锁
* 1.2 void unlock()解锁
* 2.常用的接口的实现类:
* 1. ReentrantLock implements Lock;
* 二、具体使用步骤:
* 1,在成员位置创建ReentrantLock对象(多态)
* Lock lock = new ReentrantLock();
* 2. 在线程安全的问题代码(访问共有变量的代码块)前后加上获取锁和释放锁。
* 四、代码优化:
* 1.把锁的释放放到finally语句里,无论线程语句是否异常都会开锁,不会影响其他代码是运行。
*/
public class Main {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread thread = new Thread(myRunnable);Thread thread1 = new Thread(myRunnable);Thread thread2 = new Thread(myRunnable);thread.start();thread1.start();thread2.start();}
}
MyRunnable.java
package Java学习.Java高级.多线程.线程安全问题.线程安全问题解决.解决3更高级的Lock接口;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyRunnable implements Runnable{private int tickets = 100;Lock lock = new ReentrantLock();@Overridepublic void run() {while (true){lock.lock();//获取锁,锁住if (tickets>0) {try {System.out.println(tickets + "on selling...");tickets--;Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}finally {//代码优化,把开锁放到finally,无论是否异常都会把开锁,不会影响其他线程。lock.unlock();//解开,释放。}}}}
}
输出:
100on selling…
99on selling…
98on selling…
97on selling…
96on selling…
95on selling…
94on selling…
93on selling…
…
2on selling…
1on selling…
ps:笔者因为图便利写了死循环,请输出完后关闭程序
如有任何问题欢迎评论或者私信.
Java 高级 多线程 线程安全 3 种常见解决方案教程.相关推荐
- 用10086客服热线理解Java高级多线程之线程池
Java高级多线程之线程池 客服热线案例 引入线程池 1.线程的概念 2.线程池的作用: 获取线程池 1.常用的线程池接口和类 2.代码案例 Callable接口 1.概念简述 2.应用场景 3.方法 ...
- Java面试之多线程:Java创建多线程为什么只有一种方式?
关于线程的创建,其实我一直都有话说,于是今天,我来开个头.今天依旧一样,长话短说,只谈创建多线程.你好,我是fntp!今天要跟大家分享的是博主最近面试Java实习所遇到的一些问题!那就是经常性被问到的 ...
- Java 创建一个线程的三种方式
Java 创建一个线程的三种方式 更多内容,点击了解: https://how2j.cn/k/thread/thread-start/353.html 创建多线程有3种方式,分别是继承线程类,实现Ru ...
- Java 枚举(1): 详解7种常见的用法
目录 用法一:常量 用法二:switch 用法三:向枚举中添加新方法 用法四:覆盖枚举的方法 用法五:实现接口 用法六:使用接口组织枚举 用法七:关于枚举集合的使用 JDK1.5引入了新的类型--枚举 ...
- Java高级之线程同步
本文来自刘兆贤的博客_CSDN博客-Java高级,Android旅行,Android基础领域博主 ,引用必须注明出处! 关于实现多线程的意义,"从业四年看并发"一文已经讲述,而本篇 ...
- java如何解决缓存问题_4种常见的缓存问题及解决方案详解
前言 使用缓存可以缓解大流量压力,显著提高程序的性能.我们在使用缓存系统时,尤其是大并发情况下,经常会遇到一些"疑难杂症".本文总结了一些使用缓存时常见的问题及解决方案,以后在遇到 ...
- java中创建线程的四种方式及线程池详解
众所周知,我们在创建线程时有四种方法可以用,分别是: 1.继承Thread类创建线程 2.实现Runnable接口创建线程 3.使用Callable和Future创建线程 4.使用线程池创建(使用ja ...
- Java 高级 --- 多线程快速入门
这世上有三样东西是别人抢不走的:一是吃进胃里的食物,二是藏在心中的梦想,三是读进大脑的书 多线程快速入门 1.线程与进程区别 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.线程是一组 ...
- JAVA之多线程概念及其几种实现方法优劣分析
1. 多线程 程序:指令集,静态的概念 进程:操作系统调动程序,是程序的一次动态执行过程,动态的概念 线程:在进程内的多条执行路径 Ps:单核的话进程都是虚拟模拟出来的,多核处理器才可以执行真正的多线 ...
- JAVA中创建线程的三种方法及比较
JAVA中创建线程的方式有三种,各有优缺点,具体如下: 目录 一.继承Thread类来创建线程 二.实现Runnable接口来创建线程 三.通过Callable和Future来创建线程 四.三种方式创 ...
最新文章
- python numba.jit(该装饰器用于将Python函数编译为本机代码、python运算加速器)
- 静态链表和动态链表 区别
- 全局照明算法基础——从辐射亮度到渲染方程
- 如何使用ABP进行软件开发之基础概览
- 用 X 光检测新冠肺炎?也许孪生网络+迁移学习是更好的选择!
- python3 重新运行本程序_python3+PyQt5重新实现QT事件处理程序
- 实验六 团队作业2—团队项目评审与团队项目选题报告
- [2018.08.09 T1] 数学题
- deepin下安装QT
- 解析.db文件,并且导出为sql语句
- Python 字符串前面加b,u,r的含义
- ACI注册国际心理师/营养师1903期考场规则及注意事项
- Python之京东商品秒杀
- 微信小程序 – 解决腾讯视频插件—视频只能播放广告问题
- 技术工坊|腾讯华为入局的区块链BaaS平台解决了什么问题?(上海)
- R语言使用plot函数可视化数据散点图,使用title函数为可视化图像设置自定义标题名称、自定义adj参数将标题向右侧移动
- java中定义ListNode
- 刷题-洛谷-P1179 数字统计
- 1231321321
- python-18-并行计算pp模块