线程中的同步代码块synchronized、同步方法和同步锁Lock

在学习线程的时候,因为线程的调度具有不确定性,所以银行取钱问题、多个窗口售卖火车票问题都是反应多线程的优越性以及不确定性。当程序中有多个并发线程在进入一个代码块中并且修改其中参数时,就很有可能引发线程安全问题从而造成异常。
同步代码块
所以,java在其中就引入了同步监视器来解决关于多线程的支持问题

synchronized(obj)
{
    同步代码块
}

上面就是同步的代码块方式,也就是说,当线程开始执行同步代码块之前,必须先获得对同步监视器的锁定,而且无论在什么时候,只能有一个线程可以获得对同步监视器的锁定,当同步代码执行完成之后,这个线程会释放该线程的同步监视器的锁定。
任何线程在修改指定的参数资源之前,都需要对该参数资源加锁,在加锁期间其他的线程是不能对这个参数资源进行修改的,只有在该线程完成修改并且释放对该参数的锁定之后其他线程才有机会对该参数进行修改。这样做也就是符合了“加锁–>修改–>释放”的逻辑顺序。
同步方法
其实这个还有一个同步方法,也就是用关键字synchronized来修饰一个方法,对于关键字synchronized修饰的方法,就不需要再指定同步监视器了,因为同步方法的同步监视器就是this,也就是调用了该方法的对象。

public synchronized void testThread()
{
    //需要执行的代码块
}

需要注意的是:synchronized可以修饰方法和代码块,就是不能修饰构造器和成员变量等。

同步锁
Lock提供了比synchronized更加广泛的锁定操作,能够实现更灵活的结构,而且支持多个condition对象。
在实现线程安全的控制中,比较常用的是ReentrantLock,使用该对象可以显式的加锁和释放锁,格式如下:

class A
{
    private final ReentrantLock lock=new ReentrantLock();
    public void b()
    {
        lock.lock();
        try{
                //需要执行的代码块
            }catch(Exception e){
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
    }
}

为了确保能够在必要的时候释放锁,所以上面的代码中使用finally来确保锁的释放。

你可能感兴趣的:(java)