同步:所有的线程按照顺序一个一个的进入到方法中
使用synchronized来处理同步问题
- 同步方法
- 同步代码块
synchronized的实现原理
synchronized是通过monitor机制实现的
当执行monitorenter时,首先判断该目标锁的计数器是否为0,若为0,就将计数器加一,并且当前线程就为该对象的持有线程
若计数器不为0,判断该对象的持有线程是否为当前线程,若是,就给计数器加一,若不是,就要等持有线程释放该锁
当执行monitorexit,JAVA虚拟机需要将该锁的对象的计数器减一,当计数器为0时说明该锁已经被释放
使用同步代码块
同步代码块:此代码块在任意一个时刻只有一个线程可以进入
同步代码块格式如下:
synchronized (锁的对象){
}
简单写个同步代码块的使用:
public class Main{
public static void main(String[] args) {
MyThread myThread=new MyThread();
Thread thread1=new Thread(myThread,"票务1");
Thread thread2=new Thread(myThread,"票务2");
thread1.start();
thread2.start();
}
}
class MyThread implements Runnable {
private int ticket=10;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (this){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+" 剩余票数:"+--ticket);
}
}
}
}
}
上述代码是在方法里进行synchronized的,因此可以有多个线程进入方法
使用同步方法
同步方法:此方法在任意一个时刻只有一个线程可以进入
public class Main{
public static void main(String[] args) {
MyThread myThread=new MyThread();
Thread thread1=new Thread(myThread,"票务1");
Thread thread2=new Thread(myThread,"票务2");
thread1.start();
thread2.start();
}
}
class MyThread implements Runnable {
private int ticket=10;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
this.sale();
}
}
public synchronized void sale(){
if(this.ticket>0){
System.out.println(Thread.currentThread().getName()+" 剩余票数:"+--ticket);
}
}
}
死锁的产生条件(同时满足):
- 线程互斥:共享资源只能同时被一个资源占用
- 占有且等待:线程拿到了锁1,同时不释放去申请锁2
- 不可抢占:线程1拿到了对象锁后,其他线程无法抢占该锁
- 循环等待:线程1拿到了资源锁1,去申请资源锁2,线程2拿到了资源锁2,去申请资源锁1
产生死锁时,破坏其任意一个条件就可以解除死锁