一、前言
解决线程同步问题有三种方式:同步代码块、同步方法、锁(JDK5新增)
使用synchronized
解决线程同步问题要时时刻刻注意要使用同一个同步监视器,特别是在继承创建多线程是要格外注意。
二、同步代码块
1、语法
synchronized(同步监视器){
需要被同步的代码
}
2、对语法的说明
需要被同步的代码就是操作共享数据的代码
同步监视器可以是任何类的对象,但必须是唯一的
实现创建多线程的案例中,通常用this作为同步监视器。继承创建多线程中,通常用 类名.class
充当同步监视器
3、代码演示
代码背景:创建两个窗口卖票,总票数是10张,通过实现Runnable接口创建多线程
public class TicketDome1 extends Thread {
static int ticket = 10;//多个线程访问共享资源
static Object obj = new Object();
//注Object也要静态,因为俩个人公用一个钥匙
@Override
public void run() {
//在run中模拟出所需任务
while (true) {
//为什么需要同步的代码,用同步代码块修饰,多个线程拥有一把锁,谁先获得,谁才可以进入,其他线程等待
//当持有锁的线程把同步代码中内容执行完成后,离开同步代码块会自动释放锁
synchronized (obj) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
} else
break;
}
}
}
}
//测试类
public class Text {
public static void main(String[] args) {
TicketDome1 t1 = new TicketDome1();
t1.setName("窗口1");
t1.start();
TicketDome1 t2 = new TicketDome1();
t2.setName("窗口2");
t2.start();
}
}
4、总结
这样处理可以做到线程安全,但是在同步代码块中线程是单线程执行,效率会降低
三、同步方法
1、语法
public synchronized void 方法名(){
//操作共享数据的代码
}
2、对语法的说明
同步方法仍然涉及到同步监视器,只是不需要我们显式的声明
非静态的同步方法,同步监视器是this
静态的同步方法,同步监视器是当前类本身
3、代码演示
public class TicketDome1 extends Thread {
static int ticket = 10;//多个线程访问共享资源
@Override
public void run() {
while (true) {
if (ticket > 0) {
printTicket();
} else
break;
}
}
//用synchronized修饰方法,此方法为同步方法
//锁对象默认为this,多个线程就有多把锁
public static synchronized void printTicket() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + ":" + ticket);
ticket--;
}
}
}
四、Lock方法
1、步骤
① 实例化ReentrantLock对象
② 在try块中开启锁
③ 在finally块中关闭锁
2、代码演示
public class Ticket extends Thread {
private static int ticket = 10;
//实例化ReentrantLock对象
private static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
//开启锁
lock.lock();
if (ticket > 0) {
System.out.println(getName() + "票号为:" + ticket);
ticket--;
} else {
break;
}
} finally {
//关闭锁
lock.unlock();
}
}
}
}
五、总结
synchronized和Lock的区别
- Lock是显式锁(手动开启和关闭锁);而synchronized是隐式锁,出了作用域自动释放
- Lock只能作用于代码块;而sychronized可以作用于代码块也可以作用于方法
- Lock锁,JVM花费较少时间,性能更好,锁的粒度更小,更有针对性
线程同步机制中优先使用顺序:Lock、同步代码块、同步方法;即锁的粒度越小越好。