线程的同步与死锁

线程同步的引入

之前出现的问题:
例:卖票过程中,出现了重票和错票。(线程安全问题)

出现原因:当某个线程操作车票的过程中,尚未操作完成时(被阻塞),其他线程参与进来,也操作车票。

解决方法:当一个线程在操作车票数时,其他线程不能操作进来。直到当前线程操作完成后,其他线程才能开始操作。即使当前线程出现了阻塞,也不能改变。

在Java中,我们通过同步机制,来解决线程安全问题。

synchronized实现同步

方法1:同步代码块

synchronized(同步监视器){

    //需要被同步的代码

}

说明:

操作共享数据的代码,即为需要被同步的代码。
②共享数据:多个线程共同操作的变量(车票数)。
③同步监视器:俗称:锁。任何一个类的对象,都可以充当锁(多个线程必须要共用一把锁)。
④在实现Runmable 接口创建多线程时,可考虑this 为监视器;在继承 Thread类创建多线程时,可考虑当前类为监视器。

方式2:同步方法(使用synchronized修饰方法)

public synchronized void a(...){}

1、同步方法仍有同步监视器,只是不需要显式声明。
2、非静态的同步方法,同步监视器为this;静态的为当前类本身。

线程同步的优缺点:

好处:解决了线程安全的问题。
局限性:只能有一个线程参与,相当于是一个单线程的过程,效率低。

死锁

出现原因

1、不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
2、出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续执行。

解决方法

1、专门的算法,原则。
2、减少同步资源的定义。
3、避免嵌套同步。


Lock(锁)实现同步

步骤

1、实例化ReentrantLock(重进入锁)。
2、使用 try-catch-finally 将需同步的代码包起来。
3、在 try{} 中先调用对象的lock()方法进行锁定,然后再执行业务代码。
4、在finally中调用对象的unlock()方法进行解锁。

注:如果ReentrantLock的参数为true,则表示为公平的,先进入的线程出来后会被先加载。

synchronized 和 Lock的异同

同:都可以解决线程安全问题
不同:synchronized自动释放同步监视器,Lock需手动的启动和关闭同步监视器。

优先使用顺序:Lock  >  同步代码块  >   同步方法

你可能感兴趣的:(java,开发语言)