线程同步-同步方法

防止多个线程访问数据对象时,对数据造成破坏或者是说多个线程访问同一个对象进行数据处理时,发生了错误,因此就需要线程同步。
我们来创建一个实例进行说明:
我们来构建一个信用卡账户,起初额度为100w,然后模拟透支,存款等操作。

1、创建一个非同步的实例

第一步:创建一个User对象

创建一个User对象,添加两个变量账号(code)和余额(cash);添加一个处理业务的方法oper()。
代码如下:

package thread_synchronization;

public class User {

    private String code;//账号
    private int cash;//金额

    public User(String code,int cash){
        this.code=code;
        this.cash=cash;
    }
    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public int getCash() {
        return cash;
    }

    public void setCash(int cash) {
        this.cash = cash;
    }

    /**
     * 计算剩余额度
     * @param x
     */
    public void oper(int x){
        try {
            this.cash+=x;
            System.out.println(Thread.currentThread().getName()+"运行结束,增加"+x+","+"当前余额剩余为:"+cash);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return "User{" + "code='" + code + '\'' + ",cash=" + cash + '}';
    }
}

第二步:创建线程

public class ThreadExtend_Synchronization extends Thread{

    private User user;
    private int y;

    ThreadExtend_Synchronization(String name, User user, int y){
        super(name);
        this.user=user;
        this.y=y;
    }
    @Override
    public void run() {
        user.oper(y);
    }

    public static void main(String args[]){
        User user=new User("张三",100);
        Thread thread1=new ThreadExtend_Synchronization("线程A",user,1);
        Thread thread2=new ThreadExtend_Synchronization("线程B",user,2);
        Thread thread3=new ThreadExtend_Synchronization("线程C",user,3);
        Thread thread4=new ThreadExtend_Synchronization("线程D",user,4);
        Thread thread5=new ThreadExtend_Synchronization("线程E",user,-10);
        Thread thread6=new ThreadExtend_Synchronization("线程F",user,-20);
        Thread thread7=new ThreadExtend_Synchronization("线程G",user,-30);
        Thread thread8=new ThreadExtend_Synchronization("线程H",user,-40);
        Thread thread9=new ThreadExtend_Synchronization("线程I",user,-50);
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
        thread6.start();
        thread7.start();
        thread8.start();
        thread9.start();
    }
}

第三步:运行结果

运行结果如下:

线程B运行结束,增加2,当前余额剩余为:103
线程A运行结束,增加1,当前余额剩余为:103
线程D运行结束,增加4,当前余额剩余为:107
线程E运行结束,增加-10,当前余额剩余为:97
线程C运行结束,增加3,当前余额剩余为:100
线程F运行结束,增加-20,当前余额剩余为:40
线程H运行结束,增加-40,当前余额剩余为:60
线程I运行结束,增加-50,当前余额剩余为:-10
线程G运行结束,增加-30,当前余额剩余为:-40

通过结果,我们发现,数据计算并不正确,并不是我们想要的结果,原因是因为多个线程对同一个对象user不加访问的修改其数据锁导致的。
要修改成正确的,我们只要保证每一次对User对象的oper()方法只有一个线程在访问就可以了。
这个时候我么就需要synchronized线程同步了。

2、修改成线程同步的实例

Java当中每个对象都有一个内置的锁,当程序运行到非静态的synchronized同步方法上时,自动获取当前实例的锁,获得一个对象的锁也称为获取锁、锁定对象、在对象上锁定或在对象上同步。
关于锁和同步,有以下几个要点:
(1)、只能同步方法,不能同步变量和类。
(2)、每个对象只能有一个锁,当提到同步时,应该清楚再什么条件下进行同步,再什么位置进行同步。
(3)、如果两个线程要执行一个类的synchronized方法,并且两个线程使用相同的实例来调用方法,那么一次只能拥有一个线程执行方法,另一个线程需要等待,直到锁被释放。
(4)、如果线程拥有同步方法和非同步方法,那么非同步方法可以被多个线程自由访问而不受锁的限制。
(5)、线程睡眠时,它所持有的任何锁都不会被释放。
(6)、线程可以获得多个锁。比如说在一个对象的同步方法里可以调用另外一个对象的同步方法。
(7)、同步损害并发性。应该尽可能的缩小同步范围,同步不但可以同步整个方法,还可以同步方法中的一部分代码。
我们在原先的oper()方法上加上synchronized,并在方法里加上个睡眠sleep,修改后的代码如下:

    /**
     * (1)、synchronized定义在方法上
     * (2)、计算剩余额度
     * (3)、使用synchronized锁定线程对象,实现线程同步,从而保证计算结果的正确性,如果去掉synchronized,数据会发生错误,是错误的
     * @param x
     */
    public synchronized void oper(int x){
        try {
            Thread.sleep(10L);
            this.cash+=x;
            System.out.println(Thread.currentThread().getName()+"运行结束,增加"+x+","+"当前余额剩余为:"+cash);
            Thread.sleep(10L);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

我们重新再运行,结果如下:

线程A运行结束,增加1,当前余额剩余为:101
线程I运行结束,增加-50,当前余额剩余为:51
线程H运行结束,增加-40,当前余额剩余为:11
线程G运行结束,增加-30,当前余额剩余为:-19
线程F运行结束,增加-20,当前余额剩余为:-39
线程E运行结束,增加-10,当前余额剩余为:-49
线程D运行结束,增加4,当前余额剩余为:-45
线程C运行结束,增加3,当前余额剩余为:-42
线程B运行结束,增加2,当前余额剩余为:-40

通过结果我们可以发现,每一个线程输出的结果都是正确的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值