出现原因
避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。
synchronzied
当线程试图访问同步代码时,必须先获得对象锁,退出或抛出异常时必须释放锁。synchronzied实现同步的表现形式分为:代码块同步和方法同步。
3.synchronized的使用场景
1、方法同步public synchronized void method1
2、代码块同步synchronized(this){ //TODO }
锁住的是该对象,类的其中一个实例,当该对象(仅仅是这一个对象)在不同线程中执行这个同步方法时,线程之间会形成互斥。达到同步效果,但如果不同线程同时对该类的不同对象执行这个同步方法时,则线程之间不会形成互斥,因为他们拥有的是不同的锁。
3、方法同步public synchronized static void method3
4、代码块同步synchronized(Test.class){ //TODO}同3
锁住的是该类,当所有该类的对象(多个对象)在不同线程中调用这个static同步方法时,线程之间会形成互斥,达到同步效果。
5、代码块同步synchronized(o) {}
这里面的o可以是一个任何Object对象或数组,并不一定是它本身对象或者类,谁拥有o这个锁,谁就能够操作该块程序代码。
实例
...
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
synchronized (this) {
// 输出卖票信息
if(num>0){
System.out.println(Thread.currentThread().getName() + "---sale" ----+ num--);
}
}
}
}
...
ReentrantLock锁
Lock,锁对象。在Java中锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但有的锁可以允许多个线程并发访问共享资源,比如读写锁,后面我们会分析)。在Lock接口出现之前,Java程序是靠synchronized关键字(后面分析)实现锁功能的,而JAVA SE5.0之后并发包中新增了Lock接口用来实现锁的功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁,缺点就是缺少像synchronized那样隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性,可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
1、Lock接口的主要方法
void lock(): 执行此方法时, 如果锁处于空闲状态, 当前线程将获取到锁. 相反, 如果锁已经被其他线程持有, 将禁用当前线程, 直到当前线程获取到锁.
boolean tryLock():如果锁可用, 则获取锁, 并立即返回true, 否则返回false. 该方法和lock()的区别在于, tryLock()只是"试图"获取锁, 如果锁不可用, 不会导致当前线程被禁用, 当前线程仍然继续往下执行代码. 而lock()方法则是一定要获取到锁, 如果锁不可用, 就一直等待, 在未获得锁之前,当前线程并不继续向下执行. 通常采用如下的代码形式调用tryLock()方法:
void unlock():执行此方法时, 当前线程将释放持有的锁. 锁只能由持有者释放, 如果线程并不持有锁, 却执行该方法, 可能导致异常的发生.
Condition newCondition():条件对象,获取等待通知组件。该组件和当前的锁绑定,当前线程只有获取了锁,才能调用该组件的await()方法,而调用后,当前线程将缩放锁。
2.ReentrantLock的使用
关于ReentrantLock的使用很简单,只需要显示调用,获得同步锁,释放同步锁即可。
ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁
lock.lock(); //如果被其它资源锁定,会在此等待锁释放,达到暂停的效果
try {
//操作
} finally {
lock.unlock(); //释放锁
}
3.解决线程同步的实例
...
public class Ticket implements Runnable {
// 当前拥有的票数
private int num = 100;
ReentrantLock lock = new ReentrantLock();
public void run() {
while (true) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
lock.lock();
// 输出卖票信息
if (num > 0) {
System.out.println(Thread.currentThread().getName() + ".....sale...." + num--);
}
lock.unlock();
}
}
...