Java线程同步Lock同步锁代码示例
作者:超超boy 发布时间:2023-11-17 13:23:54
java线程同步原理
java会为每个object对象分配一个monitor,当某个对象的同步方法(synchronizedmethods)被多个线程调用时,该对象的monitor将负责处理这些访问的并发独占要求。
当一个线程调用一个对象的同步方法时,JVM会检查该对象的monitor。如果monitor没有被占用,那么这个线程就得到了monitor的占有权,可以继续执行该对象的同步方法;如果monitor被其他线程所占用,那么该线程将被挂起,直到monitor被释放。
当线程退出同步方法调用时,该线程会释放monitor,这将允许其他等待的线程获得monitor以使对同步方法的调用执行下去。
注意:Java对象的monitor机制和传统的临界检查代码区技术不一样。java的一个同步方法并不意味着同时只有一个线程独占执行,但临界检查代码区技术确实会保证同步方法在一个时刻只被一个线程独占执行。Java的monitor机制的准确含义是:任何时刻,对一个指定object对象的某同步方法只能由一个线程来调用。
java对象的monitor是跟随object实例来使用的,而不是跟随程序代码。两个线程可以同时执行相同的同步方法,比如:一个类的同步方法是xMethod(),有a,b两个对象实例,一个线程执行a.xMethod(),另一个线程执行b.xMethod().互不冲突。
Lock-同步锁
Lock是java5提供的一个强大的线程同步机制--通过显示定义同步锁对象来实现同步。Lock可以显示的加锁、解锁。每次只能有一个线程对lock对象加锁。
Lock有ReadLock、WriteLock、ReentrantLock(可重入锁)
常用的就是ReentrantLock。代码如下:
代码逻辑:Account账户类,实现取钱的同步方法、DrawThread取钱的线程
Account:
package lock.reentrantlock2;
import java.util.concurrent.locks.*;
/**
*账户类,需保持同步
*/
public class Account
{
//定义锁对象
private final ReentrantLock lock = new ReentrantLock();
private String accountNo;
private double balance;
public Account(){}
public Account(String accountNo , double balance)
{
this.accountNo = accountNo;
this.balance = balance;
}
public void setAccountNo(String accountNo)
{
this.accountNo = accountNo;
}
public String getAccountNo()
{
return this.accountNo;
}
public double getBalance()
{
return this.balance;
}
public void draw(double drawAmount)
{
lock.lock();
try
{
//账户余额大于取钱数目
if (balance >= drawAmount)
{
//吐出钞票
System.out.println(Thread.currentThread().getName() +
"取钱成功!吐出钞票:" + drawAmount);
try
{
Thread.sleep(1);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
//修改余额
balance -= drawAmount;
System.out.println("\t余额为: " + balance);
}
else
{
System.out.println(Thread.currentThread().getName() +
"取钱失败!余额不足!");
}
}
finally
{
lock.unlock();
}
}
public int hashCode()
{
return accountNo.hashCode();
}
public boolean equals(Object obj)
{
if (obj != null && obj.getClass() == Account.class)
{
Account target = (Account)obj;
return target.getAccountNo().equals(accountNo);
}
return false;
}
}
DrawThread:
package lock.reentrantlock2;
/**
* 调用account取钱
*
*/
public class DrawThread extends Thread
{
//模拟用户账户
private Account account;
//当前取钱线程所希望取的钱数
private double drawAmount;
public DrawThread(String name , Account account ,
double drawAmount)
{
super(name);
this.account = account;
this.drawAmount = drawAmount;
}
//当多条线程修改同一个共享数据时,将涉及到数据安全问题。
public void run()
{
account.draw(drawAmount);
}
}
TestDraw:
package lock.reentrantlock2;
/**
*/
public class TestDraw
{
public static void main(String[] args)
{
//创建一个账户
Account acct = new Account("1234567" , 1000);
//模拟两个线程对同一个账户取钱
new DrawThread("甲" , acct , 800).start();
new DrawThread("乙" , acct , 800).start();
}
}
运行结果:
甲取钱成功!吐出钞票:800.0
余额为:200.0
乙取钱失败!余额不足!
使用Lock同步与同步方法很相似,都是“加锁--修改公共变量--释放锁”的模式,代码很容易看懂。两个线程对应一个Account对象,保证了两个线程对应一个lock对象,保证了同一时刻只有一个线程进入临界区。Lock还包含太容易Lock(),以及试图获取可中断锁的lockInterruptibly(),获取超时失效锁的tryLock(long,TimeUnit)等方法。
ReentrantLock锁具有可重入性可以对已被加锁的ReentrantLock锁再次加锁,线程每次调用lock()加锁后,必须显示的调用unlock来释放锁,有几个lock就对应几个unlock。还有把unlock放在finally代码块中,Lock在发生异常时也是不释放锁的,所以在finally中释放更安全。
总结
创建并运行一个java线程方法介绍
Java编程之多线程死锁与线程间通信简单实现代码
Java多线程编程小实例模拟停车场系统
有什么问题可以随时留言,小编会及时回复大家的。感谢朋友们对本站的支持!
来源:http://www.cnblogs.com/jycboy/p/5623113.html


猜你喜欢
- 类的实例调用成员函数的原理其实不管是通过对象实例或指针实例调用,其实底层调用的过程都是一样的,都是把当前对象的指针作为一个参数传递给被调用的
- 本文介绍了android APP登陆页面适配的实现,分享给大家,具体如下:先看效果图。登陆首页效果图原理为RootView增加监听事件,然后
- 首先先简单的说一下其3大特性的定义:封装:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。将抽象得到的数据和
- 本文实例讲述了Android使用shape使组件呈现出特殊效果的方法。分享给大家供大家参考,具体如下:使用到的布局文件<?xml ve
- 本文讲述绘制Android自定义各种图形效果,为自定义控件的入门篇 相关视频链接: Android自定义控件系列 http://edu.cs
- 本节讲运行在后台服务里的工作请求,如何向发送请求者报告状态。推荐用LocalBroadcastManager发送和接收状态,它限制了只有本a
- 工程搭建1.File->new->project;2.选择“Spring Initializr”,点击next;(jdk1.8默
- 下面的方法返回false表示网络不通// 检测网络 public static boolean checkNetworkAvailable(
- 本文实例为大家分享了C#实现猜数字小游戏的具体代码,供大家参考,具体内容如下效果如图:代码:using System;using Syste
- 1.System类System系统类,主要用于获取系统的属性数据和其他操作,因其构造方法是私有的并且类中的成员方法都是静态的,所以在使用的时
- 一、程序运行环境编译环境:IntelliJ IDEA所需测试文件:PDF、.pfx数字证书及密钥、PDF Jar包(Free Spire.P
- 一 前言此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全
- 零、业务逻辑Controller-->service接口-->serviceImpl-->dao接口-->daoIm
- 1. 首先新建一个shiroConfig shiro的配置类,代码如下:@Configurationpublic class SpringS
- 冒泡排序冒泡排序的思想:每次让当前的元素和它的下一个元素比较大小、如果前一个的元素大于后一个元素的话,交换两个元素。这样的话经历一次扫描之后
- 一、策略模式到底是什么?策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替
- 本文实例讲述了Android开发实现popupWindow弹出窗口自定义布局与位置控制方法。分享给大家供大家参考,具体如下:布局文件:主布局
- 介绍记录将elasticsearch集成到spring boot的过程,以及一些简单的应用和helper类使用。接入方式使用spring-b
- Android 7.0调用相机崩溃解决办法 错误提示:android.os.FileUriExposedException: fi
- try { // 方