1. 解决多线程安全问题的方式:
- 同步代码块
synchronized(this) {
}
- 同步方法
public synchronized void method() {
}
public static synchronized void method() {
}
JDK1.5之前才使用上述两种方式借助于:synchronized 隐式锁
。之后出现一个新的显示同步锁
- 同步锁 Lock
显示锁
显示锁:必须通过 lock() 方法上锁,通过 unlock() 方法进行释放锁
此种方式是一种更加灵活更加高级处理线程安全问题的方式,但它也存在一定的不足,需要手动(finally)释放锁。
下面使用卖票实例来模拟 Lock锁的使用:
package com.pyy.juc;
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) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
}
}
}
}
结果: 出现多个窗口卖同一张票的情况
...
2号窗口 完成售票,余票为:24
1号窗口 完成售票,余票为:23
2号窗口 完成售票,余票为:22
3号窗口 完成售票,余票为:22
1号窗口 完成售票,余票为:21
3号窗口 完成售票,余票为:20
2号窗口 完成售票,余票为:19
...
下面使用同步锁Lock- ReenTrantLock实现:
package com.pyy.juc;
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) {
lock.lock();// 加锁
try {
if(tick > 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
}
} finally {
lock.unlock();// 释放锁
}
}
}
}
结果不会出现线程安全问题。