java线程同步机制,实现同步锁

java线程同步机制
有三种方式完成同步操作:1.同步代码块。2.同步方法。3.锁机制。
同步代码块:
格式:synchronized(同步锁){ 可能会出现线程安全问题的代码(访问了共享数据的代码) }
同步锁:对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁。 1. 锁对象,可以是任意类型。2. 多个线程对象 要使用同一把锁。(注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着)
java线程同步机制,实现同步锁_第1张图片
同步方法:
java线程同步机制,实现同步锁_第2张图片
java线程同步机制,实现同步锁_第3张图片
当多个线程需要访问某个公共资源的时候,我们知道需要通过加锁来保证资源的访问不会出问题。java提供了两种方式来加锁。
一种是关键字:synchronized,一种是concurrent包下的lock锁。
synchronized是java底层支持的,而concurrent包则是jdk实现。
jvm中有三种锁:偏向锁,轻量级锁,重量级锁。
Lock锁:
Lock锁也称同步锁,加锁与释放锁方法,如下:
public void lock() :加同步锁。
public void unlock() :释放同步锁。
两者区别:最重要的是Lock是一个接口,而synchronized是一个关键字
1.Lock则完全依靠系统阻塞挂起等待线程,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁。
2.Lock底层实现基于AQS实现,采用线程独占的方式,在硬件层面依赖特殊的CPU指令(CAS)。
简单来说,ReenTrantLock的实现是一种自旋锁(状态量置1(已经在使用)或者置0的操作),通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。
3.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。
4.synchronized属于重量级锁,效率低下,实现的锁机制是可重入的,主要区别是中断控制和竞争锁公平策略,Java 6 之后,为了减少获得锁和释放锁所带来的性能消耗,引入了轻量级锁和偏向锁。
5.synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),在退出同步代码块或方法时会释放该锁,Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
6.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
7.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
使用如下步骤:

1.在成员位置创建一个ReentrantLock对象
2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
java线程同步机制,实现同步锁_第4张图片
Lock锁示例:
1. lock()
小结:该种方式获取锁不可中断,如果获取不到则一直休眠等待。
2.tryLock()
小结:当获取锁时,只有当该锁资源没有被其他线程持有才可以获取到,并且返回true,同时设置持有count为1;
当获取锁时,当前线程已持有该锁,那么锁可用时,返回true,同时设置持有count加1;
当获取锁时,如果其他线程持有该锁,无可用锁资源,直接返回false,这时候线程不用阻塞等待,可以先去做其他事情;
即使该锁是公平锁fairLock,使用tryLock()的方式获取锁也会是非公平的方式,只要获取锁时该锁可用那么就会直接获取并返回true。这种直接插入的特性在一些特定场景是很有用的。但是如果就是想使用公平的方式的话,可以试一试tryLock(0, TimeUnit.SECONDS),几乎跟公平锁没区别,只是会监测中断事件。
3. tryLock(long timeout, TimeUnit unit)
小结:获取锁成功或者超时之后返回。而且在公平锁和非公平锁的场景下都可以使用,只是会增加对中断事件的监测。
当获取锁时,锁资源在超时时间之内变为可用,并且在等待时没有被中断,那么当前线程成功获取锁,返回true,同时当前线程持有锁的count设置为1.
当获取锁时,在超时时间之内没有锁资源可用,那么当前线程获取失败,不再继续等待,返回false.
当获取锁时,在超时等待时间之内,被中断了,那么抛出InterruptedException,不再继续等待.
当获取锁时,在超时时间之内锁可用,并且当前线程之前已持有该锁,那么成功获取锁,同时持有count加1。
4.lockInterruptibly()
当获取锁时,锁资源可用,那么当前线程成功获得锁,同时持有count设置为1,返回true.
当获取锁时,锁资源可用,当前线程已持有该锁,它成功获取该锁,同时持有count增加1,返回true.
当获取锁时,锁资源不可用,那么该线程开始阻塞休眠等待,但是等待过程中如果有中断事件,那么会停止等待,立即返回.
当获取锁时,锁资源不可用,线程开始阻塞休眠等待,如果等待过程中锁资源变为可用,那么当前线程成功获得锁,同时持有count设置为1,返回true。
package com.mozi.corex.his.common;

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

public class SynchronizedDemo {
private Lock lock = new ReentrantLock();
public void lockTest(Thread thread) throws InterruptedException {
// lock.lock();//获取锁-----lock()是阻塞的,tryLock()是非阻塞的,调用后立即返回。
// tryLock()方法只有在成功获取了锁的情况下才会返回true,如果别的线程当前正持有锁,则会立即
//返回false!如果为这个方法加上timeout参数,则会在等待timeout的时间才会返回false
//或者在获取到锁的时候返回true。
//ReentrantLock提供了lock()、tryLock()、tryLock(long timeout,TimeUnit unit)、
// lock.lockInterruptibly()
if(lock.tryLock(3000, TimeUnit.MILLISECONDS)){//尝试获取锁,修改等待时间
try {
System.out.println(“线程”+thread.getName() + “获取当前锁”); //打印当前锁的名称
Thread.sleep(4000);//为看出执行效果,设置休眠时间
} catch (Exception e) {
System.out.println(“线程”+thread.getName() + “发生了异常释放锁”);
}finally {
System.out.println(“线程”+thread.getName() + “执行完毕释放锁”);
lock.unlock(); //释放锁
}

    }else{
    	System.out.println(thread.getName()+"未成功,锁占用");
    }
}
public static void main(String[] args) {
	SynchronizedDemo lockTest = new SynchronizedDemo();
    //声明一个线程 “线程一”
    Thread thread1 = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
				lockTest.lockTest(Thread.currentThread());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
    }, "thread1");
    //声明一个线程 “线程二”
    Thread thread2 = new Thread(new Runnable() {

        @Override
        public void run() {
            try {
				lockTest.lockTest(Thread.currentThread());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        }
    }, "thread2");
    // 启动2个线程
    thread2.start();
    thread1.start();

}

}
结果:
java线程同步机制,实现同步锁_第5张图片
注:Lock.tryLock()尝试获取锁及设定等待时间

你可能感兴趣的:(java,java)