并发:同一个对象被多个线程同时操作
-
一个线程持有锁会导致其他所有需要此锁的线程挂起
-
在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题
-
如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题
同步方法
-
方法里面需要修改的内容才需要锁
package com.Spp.syn;
?
// 不安全的买票
public class UnSafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"你").start();
new Thread(station,"我").start();
new Thread(station,"他").start();
}
}
?
class BuyTicket implements Runnable{// 涉及多个线程操作同一个对象
private int ticketNumbers = 10;
boolean flag = true;// 外部停止方式
同步块:
-
synchronized(Obj){}
-
Obj称之为同步监视器
-
Obj可以是任何对象,推荐使用共享资源作为同步监视器
-
同步方法中无需指定同步监视器,同步方法的同步监视器及时this,就是这个对象本身,或者是class
-
-
同步监视器的执行过程
-
第一个线程访问,锁定同步监视器,执行其中代码
-
第二个线程访问,发现同步监视器被锁定,无法访问
-
第一个线程访问完毕,解锁同步监视器
-
第二个线程访问,发现同步监视器没有锁,然后锁定并访问
-
package com.Spp.syn;
?
public class UnSafeBank {
public static void main(String[] args) {
Account account = new Account(3600,"备用金");
Drawing dra1 = new Drawing(account,280,"dra1");
Drawing dra2 = new Drawing(account,100,"dra2");
dra1.start();
dra2.start();
}
}
?
// 账户
class Account {
int money;
String name;
?
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
?
//银行:模拟取款
class Drawing extends Thread {// 不涉及多个线程操作同一个对象
Account account;
// 要取的钱
int takeMoney;
// 现在手里有多少钱
int nowMoney;
public Drawing( Account account,int takeMoney,String name){
super(name);
this.account = account;
this.takeMoney = takeMoney;
}
?
死锁
执行卡死
package com.kuang.ThreadLesson;
?
public class DeadLock {
public static void main(String[] args) {
MakeUp g1 = new MakeUp(0,"11");
MakeUp g2 = new MakeUp(1,"22");
g1.start();
g2.start();
}
}
//口红
class LipStick{
?
}
//镜子
class Mirror{
?
}
?
class MakeUp extends Thread{
// 需要的资源只有一份,用static来保证只有一份
static LipStick lipStick = new LipStick();
static Mirror mirror = new Mirror();
int choice;// 选择
String name;// 使用的人
MakeUp(int choice,String name){
this.choice = choice;
this.name = name;
}
顺利执行
private void makeup() throws InterruptedException {
if(choice == 0){
synchronized (lipStick){
System.out.println(this.name+"获得口红的锁");
Thread.sleep(100);
}
synchronized (mirror){
System.out.println(this.name+"获得镜子的锁");
}
}else{
synchronized (mirror){
System.out.println(this.name+"获得镜子的锁");
Thread.sleep(200);
}
synchronized (lipStick){
System.out.println(this.name+"获得口红的锁");
}
}
}
Lock(锁)
ReentrantLock:可重入锁
ReentrantLock类实现Lock锁
package com.kuang.ThreadLesson;
import java.util.concurrent.locks.ReentrantLock;
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 BuyTicket implements Runnable{
int ticketNumbers = 10;
//定义Lock锁
private final ReentrantLock lock = new ReentrantLock();
?
synchronized 与Lock的对比
-
Lock是显示锁(手动开启和关闭),synchronized是隐式锁,出了作用域自动释放
-
Lock只有代码块锁,synchronized有代码块锁和方法锁
-
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
-
优先使用顺序:Lock > 同步代码块 > 同步方法