Java之线程同步synchronized和Lock锁

本文详细介绍了线程同步的必要性及实现方式,包括synchronized关键字的多种应用方式和Lock接口的使用方法,并对比了对象锁与类锁的区别,以及Lock锁与synchronized锁的不同之处。

目录

1.为什么需要线程同步?

2.同步处理

2.1synchronized处理同步问题

2.1.1.同步非static的 synchronized方法---对象锁

2.1.2.同步代码块 synchronized (this)---对象锁

2.1.3.同步方法及static的synchronized方法---类锁

2.1.4synchronized(类.class)----类锁

2.1.5synchronized(object)--类锁

2.2Lock锁

3.俩个重要问题:

1.对象锁和类锁的区别

2.Lock锁和synchronized的区别

1.为什么需要线程同步?

观察以下代码的结果:

class  MyThread  implements  Runnable {
    private int ticket = 10;

    @Override
    public void run() {
        for (int i = 0; i <= 10; i++) {
            {
                if (this.ticket > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
// TODO Auto-generated catch block
                        e.printStackTrace();
                    } // 模拟网络延迟
                    System.out.println(Thread.currentThread().getName() + ",还有" + this.ticket-- + " 张票");
                }
            }
        }
    }
}


public class test {
    public static void main(String[] args) {
        MyThread myTread = new MyThread();
        Thread T1 = new Thread(myTread, "黄牛1");
        Thread T2 = new Thread(myTread, "黄牛2");
        Thread T3 = new Thread(myTread, "黄牛3");
        T1.start();
        T2.start();
        T3.start();
    }
}

结果:

 这时候看到结果中负数,这种就是不同步操作,多线程并发执行导致的,唯一的好处就是处理速度快。

2.同步处理

2.1synchronized处理同步问题

所谓的同步指的是所有的线程不是一起进入到方法中执行,而是按照顺序一个一个进来。

2.1.1.同步非static的 synchronized方法---对象锁

要使用同步代码块必须设置一个要锁定的对象,所以一般可以锁定当前对象:this,以下实例是一个实例划对象

import static java.lang.Thread.sleep;

//同步方法
class   testThread  implements  Runnable
{
    private  int  ticket=100;

    @Override
    public void run() {
        for (int i=0;i<100;i++)
        {
            try {
                this.sale();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public  synchronized  void  sale() throws InterruptedException {
        if (this.ticket>0)
        {
            sleep(20);
            System.out.println(Thread.currentThread().getName()+":还有"+this.ticket--+"张票");
        }
    }
}
public class demo {
    public static void main(String[] args) {
        testThread  thread=new testThread();
        Thread  thread1=new Thread(thread,"黄牛1");
        Thread  thread2=new Thread(thread, "黄牛2");
        thread1.start();
        thread2.start();
    }
}

2.1.2.同步代码块 synchronized (this)---对象锁

但是同步方法是在方法里拦截的,也就是说进入到方法中的线程依然可能会有多个。

class  MyTread  implements  Runnable
{
    private int ticket=10;
    @Override
    public void run() {
        for (int i = 0; i <=10; i++) {
            synchronized (this) {
                if (this.ticket > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
// TODO Auto-generated catch block
                        e.printStackTrace();
                    } // 模拟网络延迟
                    System.out.println(Thread.currentThread().getName() + ",还有" + this.ticket-- + " 张票");
                }
            }
        }
    }
}

实际上,synchronized(this)以及非static的synchronized方法,只能防止多个线程同时执行同一个对象的同步代码 段。即synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也 就是this。

2.1.3.同步方法及static的synchronized方法---类锁

import static java.lang.Thread.sleep;

class  MyThread  implements  Runnable {
   // private int ticket = 10;

    @Override
    public void run() {
        try {
            MyThread.fun();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static synchronized  void fun() throws InterruptedException {

        System.out.println("加锁的方法开始执行");
        System.out.println(Thread.currentThread().getName());
        sleep(200);
        System.out.println("加锁的方法执行结束");
    }
}

2.1.4synchronized(类.class)----类锁

class  MyThread  implements  Runnable
{
    private int ticket=10;
    @Override
    public void run() {
        for (int i = 0; i <=10; i++) {
            synchronized (MyThread.class) {
                if (this.ticket > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
// TODO Auto-generated catch block
                        e.printStackTrace();
                    } // 模拟网络延迟
                    System.out.println(Thread.currentThread().getName() + ",还有" + this.ticket-- + " 张票");
                }
            }
        }
    }
}

2.1.5synchronized(object)--类锁

2.2Lock锁

JDK1.5提供的Lock锁

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

import static java.lang.Thread.currentThread;
import static java.lang.Thread.sleep;

class MyReenrantLock  implements  Runnable
{
    private Lock  numLock=new ReentrantLock();
    @Override
    public void run() {
       for (int i=1;i<10;i++)
       {
           //加锁
           numLock.lock();
           System.out.println(Thread.currentThread().getName()+":还有"+i+"人");
           //释放锁
           numLock.unlock();
       }
    }
}
public class demo {
    public static void main(String[] args) {
        MyReenrantLock  myTread=new MyReenrantLock();
        Thread T1= new   Thread(myTread,"线程1");
        Thread T2= new   Thread(myTread,"线程2");
        Thread T3=new   Thread(myTread,"线程3");
        T1.start();
        T2.start();
        T3.start();
    }

}

在JDK1.5中,synchronized是性能低效的。因为这是一个重量级操作,它对性能最大的影响是阻塞的是实现,挂起 线程和恢复线程的操作都需要转入内核态中完成,这些操作给系统的并发性带来了很大的压力。相比之下使用Java 提供的Lock对象,性能更高一些。 到了JDK1.6,发生了变化,对synchronize加入了很多优化措施,有自适应自旋,锁消除,锁粗化,轻量级锁,偏向 锁等等。导致在JDK1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronized,在未来的版 本中还有优化余地,所以还是提倡在synchronized能实现需求的情况下,优先考虑使用synchronized来进行同步。

3.俩个重要问题:

1.对象锁和类锁的区别

  • 1.对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。
  • 2.使用对象锁的情况,只有使用同一实例的线程才会受锁的影响,多个实例调用同一方法也不会受影响类锁是加载类上的,而类信息是存在 JVM 方法区的,并且整个 JVM 只有一份,方法区又是所有线程共享的,所以类锁是所有线程共享的。

2.Lock锁和synchronized的区别

  • 1.synchronized无法判断是否获取锁的状态,Lock手动获取到锁;
  • 2.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
  • 3.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
  • 4.lock是一个接口,而synchronized是java的一个关键字,synchronized是内置的语言实现;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值