java多线程 -- 同步鎖

为了解决多线程安全问题
在 Java 5.0 之前,协调共享对象的访问时可以使用的机制只有 synchronized 和 volatile 。
Java 5.0 后增加了一些新的机制,但并不是一种替代内置锁的方法,而是当内置锁不适用时,作为一种可选择的高级功能。

隐式锁

synchronized

  1. 同步代码块;
  2. 同步方法。

显示锁 Lock

jdk 1.5 后:同步锁 Lock 需要通过 lock() 方法上锁,必须通过 unlock() 方法进行释放锁。
ReentrantLock 实现了 Lock 接口,并提供了与synchronized 相同的互斥性和内存可见性。但相较于synchronized 提供了更高的处理锁的灵活性。

Lock使用方式:

Lock lock = new ReentrantLock();
lock.lock();
try {
} finally {
lock.unlock();
}

相关API:

  1. void lock() 获取锁。
  2. void lockInterruptibly() 如果当前线程未被中断,则获取锁。
  3. Condition newCondition() 返回绑定到此 Lock 实例的新 Condition 实例。
  4. boolean tryLock() 仅在调用时锁为空闲状态才获取该锁。
  5. boolean tryLock(long time, TimeUnit unit) 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
  6. void unlock()释放锁。

不使用锁出现多线程安全问题demo:

package com.company;

public class TestLock {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        new Thread(ticket, "1号窗口").start();
        new Thread(ticket, "2号窗口").start();
        new Thread(ticket, "3号窗口").start();
    }

}

class Ticket implements Runnable{

    private int tick = 100;


    @Override
    public void run() {
        while(true){
            if(tick > 0){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                }

                System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
            }

        }
    }

}

看出现的问题(截取结果中一部分):

3号窗口 完成售票,余票为:10
1号窗口 完成售票,余票为:8
2号窗口 完成售票,余票为:8
3号窗口 完成售票,余票为:8
2号窗口 完成售票,余票为:7
1号窗口 完成售票,余票为:7
3号窗口 完成售票,余票为:7
1号窗口 完成售票,余票为:6
2号窗口 完成售票,余票为:5
3号窗口 完成售票,余票为:4
3号窗口 完成售票,余票为:3
1号窗口 完成售票,余票为:3
2号窗口 完成售票,余票为:3
3号窗口 完成售票,余票为:2
1号窗口 完成售票,余票为:0
2号窗口 完成售票,余票为:1

现在我们用Lock来进行处理:

package com.company;

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

public class TestLock {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        new Thread(ticket, "1号窗口").start();
        new Thread(ticket, "2号窗口").start();
        new Thread(ticket, "3号窗口").start();
    }

}

class Ticket implements Runnable {

    private int tick = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                if (tick > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                    }

                    System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
                }
            } finally {
                lock.unlock();
            }


        }
    }

}

看下结果(当然也是一部分),很完美解决多线程安全问题:

2号窗口 完成售票,余票为:20
2号窗口 完成售票,余票为:19
2号窗口 完成售票,余票为:18
2号窗口 完成售票,余票为:17
2号窗口 完成售票,余票为:16
2号窗口 完成售票,余票为:15
2号窗口 完成售票,余票为:14
2号窗口 完成售票,余票为:13
2号窗口 完成售票,余票为:12
2号窗口 完成售票,余票为:11
2号窗口 完成售票,余票为:10
2号窗口 完成售票,余票为:9
2号窗口 完成售票,余票为:8
2号窗口 完成售票,余票为:7
2号窗口 完成售票,余票为:6
2号窗口 完成售票,余票为:5
2号窗口 完成售票,余票为:4
2号窗口 完成售票,余票为:3
2号窗口 完成售票,余票为:2
2号窗口 完成售票,余票为:1
2号窗口 完成售票,余票为:0

 

posted @ 2017-03-30 23:54  西北野狼  阅读(243)  评论(0编辑  收藏  举报