多线程JUC 篇 2.1 创建多线程的步骤(synchronized和lock)

一 编写多线程的步骤

1.1 创建多线程的步骤

1.创建资源类,在资源类中创建属性和方法。

2.在资源类上操作方法

     1.判断

     2.干活

     3.通知

3.创建多个线程,调用资源类的方法。

1.2 synchronized 同步锁

synchronized是Java的关键字,是一种同步锁,能够修饰 一个 对象,变量,方法,来控制这个所修饰的,被顺序的访问。

解决并发无非就是加锁,保证访问共享资源的操作原子性。例如加synchronized关键字。

1.3 lock锁

1.实现和synchronized同样的功能,比synchronized 操作使用更加灵活。

2.重入锁的使用格式:

// 创建可重入锁
private final ReentrantLock lock = new ReentrantLock();
try {
    //上锁
    lock.lock();
    //功能操作
    ...
}finally {
    //解锁
    lock.unlock();
}

1.4 lock与synchronized的区别与联系

 1.synchronized是java内置的关键字,而lock不是内置,是一个类。

2.synchronized不需要手动释放锁,而lock需手动释放锁(不解锁会出现死锁,需要在 finally 块中释放锁)

3.通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到

4.Lock 可以提高多个线程进行读操作的效率(当多个线程竞争的时候)
锁会出现死锁,需要在 finally 块中释放锁)

二  使用synchronized和lock的实现案例

2.1 需求描述

假设有30张票,需要3个人进行售卖,实现准确无异常。

2.2 假设1个窗口3个人方式进行售卖

2.2.1.逻辑图

 2.2.2.代码实现

1.资源

package com.ljf.thread.juc.ticket.synch;

/**
 * @ClassName: Resources
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/08/21 20:34:42
 * @Version: V1.0
 **/
public class Resources {
    private static int ticket=100;
    public synchronized  void sell() throws InterruptedException {
        if(ticket>0){
            System.out.println("线程:"+Thread.currentThread().getName()+" 消费"+(ticket--)+"还剩余:"+(ticket));
            Thread.sleep(1000);
        }
    }
}

2.窗口任务

package com.ljf.thread.juc.ticket.synch;

import com.ljf.thread.juc.ticket.synch2.Resource;

/**
 * @ClassName: SellerTickets
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/08/21 20:35:26
 * @Version: V1.0
 **/
public class SellerTickets implements Runnable {
    private Resource resource;
    public SellerTickets(Resource r) {
        this.resource=r;
    }

    @Override
    public void run() {

        while(Resource.ticket>0){
            try {
                resource.sell();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ;
        }

    }


}

3.线程调用

package com.ljf.thread.juc.ticket.synch;

import com.ljf.thread.juc.ticket.synch2.Resource;

/**
 * @ClassName: TestResources
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/08/21 20:41:50
 * @Version: V1.0
 **/
public class TestResources {
    public static void main(String[] args) {
        Resource resource=new Resource();
       SellerTickets t= new SellerTickets(resource);
        new Thread(t,"a").start();
        new Thread(t,"b").start();
        new Thread(t,"c").start();
    }
}

 效果如下: 

2.3 假设3个窗口3个人方式进行售卖

2.3.1.逻辑图

 2.3.2.代码实现

1.资源

package com.ljf.thread.juc.ticket.synch2;

/**
 * @ClassName: Resource
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/07/18 16:38:09
 * @Version: V1.0
 **/
public class Resource {
    public  static  int ticket=30;
    public synchronized  void sell() throws InterruptedException {
        if(ticket>0){
            System.out.println("线程:"+Thread.currentThread().getName()+" 消费第"+(ticket--)+" 还剩余:"+(ticket));
            Thread.sleep(1000);
        }
    }
}

2.任务窗口

package com.ljf.thread.juc.ticket.synch2;

import com.ljf.thread.juc.ticket.synch2.Resource;

/**
 * @ClassName: SubwayTickets
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/07/18 16:23:05
 * @Version: V1.0
 **/
public class SubwayTickets implements Runnable {
    private Resource r;
    public SubwayTickets(Resource r) {
        this.r=r;
    }

    @Override
    public void run() {

        while(Resource.ticket>0){
            try {
                r.sell();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ;
        }

    }
}

3.多线程调用

package com.ljf.thread.juc.ticket.synch2;

import com.ljf.thread.juc.ticket.synch2.Resource;
import com.ljf.thread.juc.ticket.synch2.SubwayTickets;

/**
 * @ClassName: TestTicket
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/07/18 16:25:03
 * @Version: V1.0
 **/
public class TestTicket {
    public static void main(String[] args) {
       final Resource r = new Resource();
         new Thread(new SubwayTickets(r),"线程A").start();
         new Thread(new SubwayTickets(r),"线程B").start();
         new Thread(new SubwayTickets(r),"线程C").start();

        /**
        Thread t1 = new Thread(new Runnable() {
            @Override  //具体创建线程的方法是new Thread(new Runnable({ 重写run方法},线程名)
            public void run() {
                for (int i = 0; i < 40; i++) {
                    r.sell();
                }
            }
        }, "t1"
        );
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            @Override  //具体创建线程的方法是new Thread(new Runnable({ 重写run方法},线程名)
            public void run() {
                for (int i = 0; i < 40; i++) {
                    r.sell();
                }
            }
        }, "t2"
        );
        t2.start();


        Thread t3 = new Thread(new Runnable() {
            @Override  //具体创建线程的方法是new Thread(new Runnable({ 重写run方法},线程名)
            public void run() {
                for (int i = 0; i < 40; i++) {
                    r.sell();
                }
            }
        }, "t3"
        );
        t3.start();
         **/
    }

}

4.结果调用

2.4 使用lock假设1个窗口3个人方式进行售卖

2.4.1 截图如下

 1.资源类

package com.ljf.thread.juc.ticket.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @ClassName: ResourceTicket
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/07/18 17:18:35
 * @Version: V1.0
 **/
public class ResourceTicket {
    public  static  int ticket=150;
    private ReentrantLock lock=new ReentrantLock();
    public   void sell() throws InterruptedException {
        lock.lock();;
        try {
            if (ticket > 0) {
                System.out.println("线程:" + Thread.currentThread().getName() + " 消费" + (ticket--) + "还剩余:" + (ticket));
               // Thread.sleep(100);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }

    }
}

2.任务窗口 

package com.ljf.thread.juc.ticket.lock;

/**
 * @ClassName: TicketWindow
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/07/18 17:20:25
 * @Version: V1.0
 **/
public class TicketWindow implements Runnable{
    private ResourceTicket resourceTicket;
    public TicketWindow(ResourceTicket resourceTicket) {
        this.resourceTicket=resourceTicket;
    }

    @Override
    public void run() {
        while(ResourceTicket.ticket>0){
            try {
                resourceTicket.sell();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3.多线程执行

package com.ljf.thread.juc.ticket.lock;

/**
 * @ClassName: TestTicketByLock
 * @Description: TODO
 * @Author: liujianfu
 * @Date: 2022/07/18 17:22:16
 * @Version: V1.0
 **/
public class TestTicketByLock {
    public static void main(String[] args) {
        ResourceTicket resourceTicket=new ResourceTicket();
        TicketWindow ticketWindow=new TicketWindow(resourceTicket);
        new Thread(ticketWindow,"A").start();
        new Thread(ticketWindow,"B").start();
        new Thread(ticketWindow,"C").start();
    }
}

效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值