zoukankan      html  css  js  c++  java
  • Java多线程-synchronized与ReentrantLock

    java中多线程非常重要,尤其在高并发的时候,多线程和线程之间的通信尤为重要。下面用一个抢车票的例子来演示多线程。

    场景

    现有余票100张,多个人(多个线程)来抢票。

    创建多线程

    库存100张票

    public class Tickets {
            // 库存
            private static int num = 100;
    		// 买票的方法
            public static int buyTicket(){
                    if (Tickets.num <= 0){
                            System.out.println("无余票");
                            return 0;
                    }
                    Tickets.num--;
                    System.out.println("还剩" + Tickets.num);
                    return Tickets.num;
            }
    }
    

    买票的操作,该类要实现Runnable接口,操作放在run()方法中。也可以继承Thread类,也可以在Runnable中使用lambda表达式加锁后,用lambda表达式试试

    public class BuyTicket implements Runnable{
        public String name = "";
        public BuyTicket(String name) {
            this.name = name;
        }
        public void buy() {
            int buyTicket = Tickets.buyTicket();
            System.out.println(this.name + "买到了第" + buyTicket + "张票");
        }
        @Override
        public void run() {
                buy();
        }
    }
    

    测试

    public class TicketTest{
        public static final int MAX_THREAD_NUM = 100;
        public static void main(String[] args) {
            for (int i = 0; i < TicketTest.MAX_THREAD_NUM; i++) {
                BuyTicket buyTicket = new BuyTicket("客户" + i);
                new Thread(buyTicket).start();
            }
        }
    
    }
    

    多线程已经创建完毕,这样就OK了吗?运行看看效果

    客户36买到了第40张票
    客户87买到了第41张票
    客户86买到了第41张票
    客户89买到了第42张票
    

    ???黑人问号

    一张票被重复购买了这么多次。

    必须要采取一些措施才能不发生这种情况了。

    同步

    Java SE 5之前使用synchronized关键字同步,Java SE 5之后引入ReentrantLock对象。

    ReentrantLock

    当需要手动的加锁,释放锁的时候,使用该方式。

    通过ReentrantLock对象,可以加锁和释放锁。

    Lock myLock = new ReentrantLock();
    myLock.lock();
    try{
        ...
    }
    ...
    finally{
        myLock.unlock();
    }
    

    条件对象

    Condition xx;
    myLock.lock();
    xx = myLock.newCondition();
    if (余票<0){
        // 阻塞自己
        xx.await();
    }
    

    条件对象除了await方法,还有唤醒的方法。signal方法在该条件的等待集合中随机的唤醒一个,signalAll唤醒全部在该条件的等待集合中线程。

    synchronized

    当不需要手动加锁,释放锁的,有需要同步机制的时候,使用该关键字。

    修改后:

    票的库存 获取票的方法要加锁,每次只能一个线程访问。

    0-110,有110个人

    0-100,有99张票,有11个人买不到票

    public class Tickets {
            private static int num = 100;
            public synchronized static int buyTicket(){
                    if (Tickets.num <= 0){
                            System.out.println("无余票");
                            return 0;
                    }
                    Tickets.num--;
                    return Tickets.num;
            }
    }
    

    买票 不用实现Runnable接口,在测试类中通过lambda表达式。

    public class BuyTicket{
        public String name = "";
        public BuyTicket() {
        }
        public BuyTicket(String name) {
            this.name = name;
        }
        public void buy() {
            int buyTicket = Tickets.buyTicket();
            System.out.println(this.name + "买到了第" + buyTicket + "张票");
        }
    
    }
    

    测试类

    public class TicketTest{
        public static final int MAX_THREAD_NUM = 110;
        public static void main(String[] args) {
            for (int i = 0; i < TicketTest.MAX_THREAD_NUM; i++) {
                int customer = i;
                Runnable r = ()->{
                    BuyTicket buyTicket = new BuyTicket("客户" + customer);
                    buyTicket.buy();
                };
                new Thread(r).start();
            }
        }
    
    }
    

    线程的几种状态

    • New(新创建): 当用new操作符创建一个新线程时,如new Thread(r),该线程还没有运行,状态是new
    • Runnable(可运行): 当调用了线程的start()方法的时候,该线程的方法即是runnable。调用了start()方法之后,该线程可能正在运行,也可能没有在运行,要看操作系统调度的时间
    • Blocked(被阻塞)
    • Waiting(等待)
    • Timed waiting(计时等待)
    • Terminated(被终止)

    想要获取该线程的状态,可以调用getState()方法。

  • 相关阅读:
    刷题柱 -- 暂封
    模板重搭建計劃
    思路与好题记录与小技巧
    错误记录
    随便记点东西……
    图床
    杂碎的小技巧
    hnsdfz -- 6.21 -- day7
    hsdf -- 6.21 -- day6
    hnsdfz -- 6.20 -- day5
  • 原文地址:https://www.cnblogs.com/to-red/p/12158016.html
Copyright © 2011-2022 走看看