Java使用线程同步解决线程安全问题详解(java线程间同步)

网友投稿 272 2022-07-31


第一种方法:同步代码块:

作用:把出现线程安全的核心代码上锁

原理:每次只能一个线程进入,执行完毕后自行解锁,其他线程才能进来执行

锁对象要求:理论上,锁对象只要对于当前同时执行的线程是同一个对象即可

缺点:会干扰其他无关线程的执行

所以,这种只是理论上的,了解即可,现实中并不会这样用

public class 多线程_4线程同步 {

public static void main(String[] args) {

//定义线程类,创建一个共享的账户对象

account a=new account("abc",10000);

//创建两个取钱的线程对象

new drawthread(a,"小明").start();

new drawthread(a,"小红").start();

}

}

//取钱的线程类

class drawthread extends Thread{

//接收处理的账户对象

private account acc;

public drawthread(account acc,String name){

super(name);

this.acc=acc;

}

public void run(){

//取钱

acc.drawmoney(10000);

}

}

class account{

private String cartId;

private double money;//账户余额

public account() {

}

public account(String cartId, double money) {

this.cartId = cartId;

this.money = money;

}

public String getCartId() {

return cartId;

}

public void setCartId(String cartId) {

this.cartId = cartId;

}

public double getMoney() {

return money;

}

public void setMoney(double money) {

this.money = money;

}

public void drawmoney(double money) {

//先获取是谁来取钱,线程名即是人名

String name=Thread.currentThread().getName();

//同步代码块

//作用:把出现线程安全的核心代码上锁

//原理:每次只能一个线程进入,执行完毕后自行解锁,其他线程才能进来执行

//锁对象要求:理论上,锁对象只要对于当前同时执行的线程是同一个对象即可

//缺点:会干扰其他无关线程的执行

WvTMBJYif synchronized ("遇安") {//"锁名自取,无意义"

//判断账户是否够钱

if(this.money>=money){

//取钱

System.out.println(name+"来取钱成功,取了:"+money);

//更新金额

this.money-=money;

System.out.println(name+"取钱后剩余:"+this.money);

}else{

//余额不足

System.out.println(name+"来取钱,但余额不足!");

}

}

}

}

规范上:建议使用共享资源作为锁对象

对于实例化方法建议使用this作为锁对象

对于静态方法,建议使用字节码(类名.class)对象作为锁对象

//接上文代码

//实例化方法建议使用this作为锁对象

synchronized (this) {

//判断账户是否够钱

if(this.money>=money){

//取钱

System.out.println(name+"来取钱成功,取了:"+money);

//更新金额

this.money-=money;

System.out.println(name+"取钱后剩余:"+this.money);

}else{

//余额不足

System.out.println(name+"来取钱,但余额不足!");

}

}

//静态方法建议使用类名.class作为锁对象

//每次只有一个线程能锁这个类,而类也是唯一的

public static void run(){

synchronized(account.class){

}

}

第二种方法:同步方法

//同步方法

public synchronized void drawmoney(double money) {

//先获取是谁来取钱,线程名即是人名

String name=Thread.currentThread().getName();

//判断账户是否够钱

if(this.money>=money){

//取钱

System.out.println(name+"来取钱成功,取了:"+money);

//更新金额

this.money-=money;

System.out.println(name+"取钱后剩余:"+this.money);

}else{

WvTMBJYif//余额不足

System.out.println(name+"来取钱,但余额不足!");

}

}

那么同步代码块和同步方法哪个好一点呢?

答案是:同步代码块

因为同步代码块锁的范围更小一点,同步方法锁的范围更大一点

但其实在现实中同步方法用的更多一点,因为代码简洁好写一点,更方便

第三种方法:Lock锁

JDK5后出现,更加灵活方便

Lock是接口不能直接实例化,我们需要采用它的实现类ReentrantLock来构建Lock锁对象

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class 多线程_4线程同步Lock锁 {

public static void main(String[] args) {

//定义线程类,创建一个共享的账户对象

account a=new account("abc",10000);

//创建两个取钱的线程对象

new drawthread(a,"小明").start();

new drawthread(a,"小红").start();

}

}

//取钱的线程类

class drawthread2 extends Thread{

//接收处理的账户对象

private account acc;

public drawthread2(account acc,String name){

super(name);

this.acc=acc;

}

public void run(){

//取钱

acc.drawmoney(10000);

}

}

class account2{

private String cartId;

private double money;//账户余额

//final修饰后:锁对象是唯一的和不可替换的

//Lock是接口不能直接实例化,我们需要采用它的实现类ReentrantLock来构建Lock锁对象

private final Lock lock=new ReentrantLock();

public account2() {

}

public account2(String cartId, double money) {

this.cartId = cartId;

this.money = money;

}

public String getCartId() {

return cartId;

}

public void setCartId(String cartIdWvTMBJYif) {

this.cartId = cartId;

}

public double getMoney() {

return money;

}

public void setMoney(double money) {

this.money = money;

}

public void drawmoney(double money) {

//先获取是谁来取钱,线程名即是人名

String name=Thread.currentThread().getName();

lock.lock();//上锁

//判断账户是否够钱

try {

if(this.money>=money){

//取钱

System.out.println(name+"来取钱成功,取了:"+money);

//更新金额

this.money-=money;

System.out.println(name+"取钱后剩余:"+this.money);

}else{

//余额不足

System.out.println(name+"来取钱,但余额不足!");

}

//防止代码出现bug而不能解锁

} finally {

lock.unlock();//解锁

}

}

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:spring cloud eureka注册原理
下一篇:Java详解使用线程池处理任务方法(java中的线程池问题)
相关文章