1、synchronized
(1)创建资源类
public int number代表门票的数量。
public synchronized void sale();卖票的方法,注意要使用sysnchronized修饰,才是使得这个方法能够自动上锁、自动解锁。
// 创建资源类,定义属性和操作方法
class Ticket{
// 定义票数
public int number = 30;
// 方法卖票
public synchronized void sale() {
// 判断当前是否还有票可卖
if (this.number > 0) {
System.out.println(Thread.currentThread().getName()+"卖出1张 剩余 " + --number);
}
}
}
(2)main方法
new Thread(Runnable对象,自定义线程名称);
start();代表启动线程的方法
public static void main(String[] args) {
// 创建对象
Ticket ticket = new Ticket();
// 创建三个线程
Thread aa = new Thread(new Runnable() {
@Override
public void run() {
// 调用买票的方法
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "aa");
// 创建三个线程
Thread bb = new Thread(new Runnable() {
@Override
public void run() {
// 调用买票的方法
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "bb");
// 创建三个线程
Thread cc = new Thread(new Runnable() {
@Override
public void run() {
// 调用买票的方法
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "cc");
// 线程启动
aa.start();
bb.start();
cc.start();
}
(3)测试
(4)完整代码
package sync;
public class SaleTickets {
public static void main(String[] args) {
// 创建对象
Ticket ticket = new Ticket();
// 创建三个线程
Thread aa = new Thread(new Runnable() {
@Override
public void run() {
// 调用买票的方法
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "aa");
// 创建三个线程
Thread bb = new Thread(new Runnable() {
@Override
public void run() {
// 调用买票的方法
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "bb");
// 创建三个线程
Thread cc = new Thread(new Runnable() {
@Override
public void run() {
// 调用买票的方法
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}
}, "cc");
// 线程启动
aa.start();
bb.start();
cc.start();
}
}
// 创建资源类,定义属性和操作方法
class Ticket{
// 定义票数
public int number = 30;
// 方法卖票
public synchronized void sale() {
// 判断当前是否还有票可卖
if (this.number > 0) {
System.out.println(Thread.currentThread().getName()+"卖出1张 剩余 " + --number);
}
}
}
2、Lock
我们可以从文档看到,又三个类实现了Lock接口,本次我们采用ReentrantLock。
(1)建立资源类
// 创建可重入锁(可以多次使用的锁)
private final Lock lock = new ReentrantLock();
// 资源类
class LTicket{
// 票的数量
private int number = 30;
// 创建可重入锁
private final Lock lock = new ReentrantLock();
// 买票方法
public void sale() {
// 上锁
lock.lock();
// 买票
try {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "买出了1张票,还剩下 " + --number + "张");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
}
(2)main方法
此处我们采用了lambda表达式来创建线程。(参数)->{方法};
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "BB").start();
public static void main(String[] args) {
LTicket ticket = new LTicket();
// lambda表达式方法创建线程
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "AA").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "BB").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "CC").start();
}
}
(3)测试
(4)整体代码
package lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LSaleTicket {
public static void main(String[] args) {
LTicket ticket = new LTicket();
// lambda表达式方法创建线程
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "AA").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "BB").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
}, "CC").start();
}
}
// 资源类
class LTicket{
// 票的数量
private int number = 30;
// 创建可重入锁
private final Lock lock = new ReentrantLock();
// 买票方法
public void sale() {
// 上锁
lock.lock();
// 买票
try {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "买出了1张票,还剩下 " + --number + "张");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 解锁
lock.unlock();
}
}
}
3、Lock 与的 Synchronized 区别
- Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内 置的语言实现;
- synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现 象发生;而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很 可能造成死锁现象,因此使用 Lock 时需要在 finally 块中释放锁;
- Lock 可以让等待锁的线程响应中断,而 synchronized 却不行,使用 synchronized 时,等待的线程会一直等待下去,不能够响应中断;
- 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
- Lock 可以提高多个线程进行读操作的效率。 在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源 非常激烈时(即有大量线程同时竞争),此时 Lock 的性能要远远优于 synchronized。