Java多线程第二弹之Lock初体验

前言

到了紧张的秋招时间点了,本想自己总结一遍所有知识点.后来看到各种大大小小其他人总结好的排版精美的文档,不禁有点灰心.经历了秋招的捶打才发现,如果仅仅依靠找到的内容,不经过自己的思考,总是会有所欠缺.要坚持写总结,积少成多,总会有进步.

我一直都觉得锁的概念很模糊,总想弄懂,也看过一些文章,但总是不能很好的理解.

当多个线程访问同一个资源(我对资源的通俗理解就是某一个变量/数据/对象 - 个人理解,不对之处还请指正.)的时候,如果同时进行修改,可能就会造成和预期不一样的后果.

package com.icebear.jsutforfun.thread.lockdemo;

public class NoLock {
    public static void main(String[] args) {
        InnerResource innerResource = new InnerResource();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    innerResource.addNum();
                }
            }, "threadName").start();
        }
        System.out.println("最终的结果:" + innerResource.getNum());	// 小于10000
    }
}
// 资源类
class InnerResource {
	// 访问的资源 num
    private int num;
    public int getNum() {
        return num;
    }
    public void addNum() {
        num++;
    }
}

造成这种结果的原因就是JMM(Java内存模型).线程对变量的操作不能直接在主内存中完成,需要将变量的数据拷贝到属于自己的工作空间完成,最后再将结果提交到主内存当中,但是在这个过程中就会造成数据的不一致.

线程同步的方式Lock

掏出经典的买票案例:

package com.icebear.jsutforfun.thread.lockdemo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockDemo implements Runnable {

    private int tickets = 200;
    private Lock lock = new ReentrantLock();
    
    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + "我不需要争抢!");
            try {
                lock.lock();
                if (tickets-- > 0) {
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "销售了第" + tickets + "张票");
                } else {
                    break;
                }
            } finally {
                lock.unlock();
                try {
                	// 这里主要是让其他线程参与争抢
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这里抛出一个新问题,线程同步的方式.临界信号事互斥
这里从 lock()unlock()中间这段使用锁同步的代码就叫做临界区.

public class Test {
    public static void main(String[] args) {
        LockDemo lockDemo = new LockDemo();
        Thread thread1 = new Thread(lockDemo);
        Thread thread2 = new Thread(lockDemo);
        thread1.start();
        thread2.start();
    }
}

这里的thread1thread2传入的是同一个lockDemo对象,所以在进行同步的时候,使用的锁是同一个lockDemo对象的锁.
被线程操作的需要进行同步的对象,我们就可以理解为资源类.
假设thread1先执行到临界区代码,此时thread2的访问就会被阻塞,只有当thread1执行完成之后,thread2才能够对lockDemo对象中的变量进行修改.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值