Java中多线程的使用(超级超级详细)线程安全+线程锁原理解析+保证线程安全的三种方式 (同步代码块+同步方法+lock锁) 5
Java中多线程的使用(超级超级详细)线程安全+保证线程安全的三种方式 (同步代码块+同步方法+lock锁) 5
当我们使用多线程访问同一个资源时,且多个线程对资源有写的 操作就容易出现线程安全问题,java为了解决线程安全问题引入了同步机制来解决,即在一个线程使用公共代码块的时候另一个线程不可以使用 下面我用一个抢票的案例来给大家讲解保证线程安全的几种方式 首先我们先来看看没有使用锁的情况下出现的情况
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
//设置买票的线程任务
public void run(){
while(true) {
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
}
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
出现的问题 出现负数的票与重复票
对于线程安全原理不懂的兄弟可以去看看我的另一篇文章 链接:https://blog.csdn.net/pjh88/article/details/107359745
下面演示加锁的情况
方法一:同步代码块
同步代码块:synchronized关键字可以用于某个区块中,表示对这个区块的资源实行互斥访问 synchronized(同步锁){ 需要同步操作的代码 } 同步锁: 对象的同步锁只是一个概念,可以想象为在改对象上上了一把锁 1.锁可以是任意的类型 2.多个线程对象要使用同一把锁 任何时候都最多允许一个对象拥有同步锁谁拿到锁就谁进入同步代码块 使用以下代码块来演示
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
java.lang.Object object=new java.lang.Object();
//设置买票的线程任务
public void run(){
while(true) {
synchronized (object){
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
}
}
结果 可以发现没有线程不安全的情况出现
同步代码块原理解析:
同步方法
什么是同步方法? 使用synchronized修饰的方法叫做同步方法,保证线程安全,当a线程执行该方法的时候,其他线程只可以在方法外等待 public synchornized void method(){ 可能产生线程安全的代码块 } 那么锁对象在哪呢? 锁对象是隐藏的,谁调用这个方法谁就是隐藏的锁对象, 对于非static方法锁对象就是this 对于static方法锁对象是类名.class 上代码
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
java.lang.Object object=new java.lang.Object();
//设置买票的线程任务
public void run(){
while(true) {
shuchu();
}
}
public synchronized void shuchu(){
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
结果 由结果可以看出没有出现线程安全的问题
另一种实现方法
上代码
package ThreadSafe;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
java.lang.Object object=new java.lang.Object();
//设置买票的线程任务
public void run(){
while(true) {
shuchu();
}
}
public void shuchu(){
synchronized(this) {
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
}
}
}
}
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
所得的结果和上面是一样的
Lock锁
java.util.concurrent.locks.Lock 机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作, 同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象。 Lock锁的功能 public void lock()加同步锁 public void unlock() 释放同步锁
下面使用一段代码演示
package ThreadSafe;
public class Main {
public static void main(String[] args) {
//创建Runable实现对象
ThreadSafe threadSafe = new ThreadSafe();
//创建Thread类对象
Thread one = new Thread(threadSafe, "一号");
Thread two = new Thread(threadSafe, "二号");
Thread three = new Thread(threadSafe, "三号");
one.start();
two.start();
three.start();
}
}
package ThreadSafe;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadSafe implements Runnable {
//定义一个多线程共享的 票源
private int ticketsum=100;
ReentrantLock lock=new ReentrantLock();
//设置买票的线程任务
public void run(){
while(true) {
shuchu();
}
}
public void shuchu(){
while (true){
lock.lock();
//判断还有没有票
if (ticketsum > 0) {
try {
Thread.sleep(10);
String name = Thread.currentThread().getName();
System.out.println(name + "正在卖:" + ticketsum);
ticketsum--;
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
}
以上就是java锁的一些基本知识,如有错误还请各位批评指正,喜欢我的文章的可以关注我,也可以点赞收藏支持一下
- Windows Server 2008 R2 Server Core 的 Microsoft .NET Framework 4安装程序
- [C#6] 4-string 插值
- 使用API Key验证WCF Data Service
- WordPress By Example:一个WordPress 主题搜索引擎
- jquery mobile 移动web(4)
- [C#6] 3-null 条件运算符
- ServiceStack.Redis 使用教程
- WordPress 标签页面只有一篇文章时自动跳转到该文章
- OS X 上使用.NET开发应用程序
- [C#6] 2-nameof 运算符
- Key-Value Coding(KVC),Key-Value Observing(KVO)和Cocoa Bindings for MonoMac
- [C#6] 7-索引初始化器
- jquery mobile 移动web(3)
- 卷积神经网络详解(二)——自己手写一个卷积神经网络
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- pandas 一维台账数据与二维表格数据的转换
- Flutter基础widgets教程-Row篇
- padans 关于数据处理的杂谈 -- 时序数
- python pandas DataFrame 关于重复索引取值的一些坑
- selenium webdriver 如何添加cookie
- Flutter基础widgets教程-Scaffold篇
- python selenium 微信公众号历史文章随手一点就返回首页?郁闷之下只好将他们都下载下来。
- Flutter基础widgets教程-SimpleDialog篇
- python selenium 关于将网页打包为静态网页(mhtml)下载。
- Redis:哨兵
- Python中设置指定窗口为前台活动窗口(最顶层窗口)win32gui
- 关于pandas.eval使用的一些问题。
- Flutter基础widgets教程-Slider篇
- 带你认识Pytest(三)
- Additive Powers-of-Two (APoT) Quantization:硬件友好的非均匀量化方法