Synchronized与Lock
高并发场景
多个线程对同一资源对象进行操作时,会产生高并发场景。
加锁
- synchronized
- 同步方法:看起来锁的是方法,实际锁的是对象this
- 同步代码块:锁的是共享资源对象
- Lock-可重入锁
- 使用ReentrantLock类来实现,ReentrantLock类实现了Lock接口
同步方法:
package com.edgar.syn;
import java.util.concurrent.locks.ReentrantLock;
//synchronized是隐式锁,出了作用域自动释放,有代码块锁和方法锁
//Lock可重入锁,显示锁,只有代码块锁,JVM将花费较少的时间来调度线程,性能更好
//优先使用顺序:Lock>同步代码块>同步方法
//不安全的买票
public class TestLock {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"小明").start();
new Thread(buyTicket,"小红").start();
new Thread(buyTicket,"黄牛").start();
}
}
class TestLock2 implements Runnable{
private int ticketNums=10000;//总票数
private boolean flag=true;//停止标志位
private final ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while(flag){
try {
lock.lock();//加锁
buyTicket();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
//买票
//synchronized 同步方法,锁的是this
public void buyTicket() throws InterruptedException {
//判断是否还有票
if(ticketNums<=0){
flag=false;
return;
}
System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNums--)+"张票");
}
}
同步代码块:
package com.edgar.syn;
//不安全的取钱
//两个人去银行取钱
public class UnSafeBank {
public static void main(String[] args) {
Account account = new Account(100, "结婚基金");
Drawing you = new Drawing(account, 50, "you");
Drawing youGril = new Drawing(account, 100, "youGril");
youGril.start();
you.start();
}
}
class Account {
int money;
String cardName;
public Account(int money, String cardName) {
this.money = money;
this.cardName = cardName;
}
}
class Drawing extends Thread {
Account account;
int drawMoney;
int nowMoney;
public Drawing(Account account, int drawMoney, String name) {
super.setName(name);
this.account = account;
this.drawMoney = drawMoney;
}
@Override
public void run() {
//同步块,锁的是同一资源的对象
synchronized (account) {
if (account.money- drawMoney<= 0) {
System.out.println("结婚基金取完了");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡内余额
account.money = account.money - drawMoney;
//你手里的钱
nowMoney = nowMoney + drawMoney;
System.out.println(account.cardName + "余额" + account.money);
System.out.println(this.getName() + "手里的钱" + nowMoney);
}
}
}
Lock:
package com.edgar.syn;
import java.util.concurrent.locks.ReentrantLock;
//synchronized是隐式锁,出了作用域自动释放,有代码块锁和方法锁
//Lock可重入锁,显示锁,只有代码块锁,JVM将花费较少的时间来调度线程,性能更好
//优先使用顺序:Lock>同步代码块>同步方法
//不安全的买票
public class TestLock {
public static void main(String[] args) {
BuyTicket buyTicket = new BuyTicket();
new Thread(buyTicket,"小明").start();
new Thread(buyTicket,"小红").start();
new Thread(buyTicket,"黄牛").start();
}
}
class TestLock2 implements Runnable{
private int ticketNums=10000;//总票数
private boolean flag=true;//停止标志位
private final ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while(flag){
try {
lock.lock();//加锁
buyTicket();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//解锁
}
}
}
//买票
//synchronized 同步方法,锁的是this
public void buyTicket() throws InterruptedException {
//判断是否还有票
if(ticketNums<=0){
flag=false;
return;
}
System.out.println(Thread.currentThread().getName()+"买到了第"+(ticketNums--)+"张票");
}
}
Synchronized与Lock的对比
- synchronized是隐式锁,出了作用域自动释放,有代码块锁和方法锁
- Lock是显示锁,只有代码块锁,JVM将花费较少的时间来调度线程,性能更好
- 优先使用顺序:Lock>同步代码块>同步方法