JUC之Synchronized与Lock

目录

Synchronized

作用

用法

案例

修饰方法

修饰代码块

修饰类

注意

Lock

主要方法

使用

ReentrantLock

ReentrantReadWriteLock

特点

常用方法

区别


Synchronized

称之为”同步锁

作用

        保证在同一时刻, 被修饰的代码块或方法只会有一个线程执行,以达到保证并发安全的效果

用法

        1.修饰方法:方法锁,锁的对象是当前对象

        2.修饰静态方法:类锁,锁的对象是当前的类,实际是这个类的.class对象

        3.修饰代码块:对象锁,锁的对象是synchronized修饰的对象

案例

修饰方法

public class TestThread {
    public static void main(String[] arge){
        Ticket ticket = new Ticket();

        new Thread(()->{
            for(int i=1;i<40;i++){
                ticket.ticket();
            }
        },"A").start();
        new Thread(()->{
            for(int i=1;i<40;i++){
                ticket.ticket();
            }
        },"B").start();
        new Thread(()->{
            for(int i=1;i<40;i++){
                ticket.ticket();
            }

        },"C").start();
    }
}

class Ticket{
    private int num = 20;

    synchronized void ticket(){
        if(num > 0){
            System.out.println(Thread.currentThread().getName()+"剩余票数:"+num--);
        }
    }
}

修饰代码块

class SyncThread implements Runnable {
       private static int count;
 
       public SyncThread() {
          count = 0;
       }
 
       public  void run() {
          synchronized(this) {
             for (int i = 0; i < 5; i++) {
                try {
                   System.out.println(Thread.currentThread().getName() + ":" + (count++));
                   Thread.sleep(100);
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
             }
          }
       }
 
       public int getCount() {
          return count;
       }
}
 
public class Demo00 {
    public static void main(String args[]){     
        SyncThread s = new SyncThread();
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        
        t1.start();
        t2.start();
    }
}

修饰类

        给class加锁和上例的给静态方法加锁是一样的,所有对象公用一把锁

class ClassName {
   public void method() {
      synchronized(ClassName.class) {

      }
   }
}

注意

        1.在定义接口方法时不能使用synchronized关键字;构造方法不能使用synchronized关键字

        2.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制

        3.每个对象只有一个锁与之相关联,谁拿到这个锁谁就可以运行它所控制的那段代码

Lock

Lock是一个同步线程机制;

主要方法

        lock():获取锁,加锁

        tryLock():判断锁是否可用

        unlock():释放锁

使用

public class TestThread2 {
    public static void main(String[] arge){
        Ticket2 ticket = new Ticket2();

        new Thread(()->{
            for(int i=1;i<40;i++){
                ticket.ticket();
            }
        },"A").start();
        new Thread(()->{
            for(int i=1;i<40;i++){
                ticket.ticket();
            }
        },"B").start();
        new Thread(()->{
            for(int i=1;i<40;i++){
                ticket.ticket();
            }

        },"C").start();
    }
}

class Ticket2{
    private int num = 20;

    void ticket(){
        Lock lock = new ReentrantLock();

        lock.lock();

        try{
            if(num > 0){
                System.out.println(Thread.currentThread().getName()+"剩余票数:"+num--);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

ReentrantLock

        重入锁也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。避免死锁问题

public class ReentrantDemo implements Runnable {
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        set();
    }
    public void set() {
        try {
            lock.lock();
            System.out.println("set 方法");
            get();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();// 必须在finally中释放
        }
    }
 
    public void get() {
 
        try {
            lock.lock();
            System.out.println("get 方法");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public static void main(String[] args) {
        ReentrantDemo reentrantDemo = new ReentrantDemo();
        new Thread(reentrantDemo).start();
    }
}

        同一个线程,首先在set方法中获取锁,然后调用get方法,get方法中重复获取同一个锁。两个方法都执行成功

ReentrantReadWriteLock

读写锁,可以分别获取读锁或写锁。

特点

        读锁使用共享模式;写锁使用独占模式;读锁可以在没有写锁的时候被多个线程同时持有,写锁是独占的。当有读锁时,写锁就不能获得;而当有写锁时,除了获得写锁的这个线程可以获得读锁外,其他线程不能获得读锁

常用方法

        writeLock():获取写锁

        readLock():获取读锁

区别

        1.synchronized内置关键字;lock是一个Java类

        2.synchronized无法判断锁状态;lock可以判断是否获取到锁

        3.synchronized会自动释放锁;lock必须手动释放锁,不释放会造成死锁

        4.synchronized可重入锁,不可以中断,非公平;lock可重入锁,可以判断锁,非公平(可以设置)

        5.synchronized适合锁少量的代码同步问题;lock适合锁大量的同步代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值