Java 多线程 同步锁
多线程 处理同一资源
典型案例 不同途径 对某场电影的票数 进行售卖 假设没有退票 各线程的任务都是售卖票 使票数不断减少
为避免 多线程售同一张票 出现票数被减为负 引入“线程同步”
同步 保证了 安全性 因为没有锁的线程不能执行 (线程只有先拿到同步锁 才能执行售票 , 其它线程 没有拿到同步锁 则不能执行 存在了先后顺序)
同步方法的执行 需要进行 同步锁是否拥有的判断 因此这种添加了synchronized关键字修饰的方法 这种方法的运行速度较慢(StringBuilder类的方法 都是不同步的方法 StringBuffer类的 方法 都是同步的方法)
同步锁 其专业词汇 被称为 对象监视器 ------ java.lang包下的异常类 IllegaMonitorStateEXception 无效的监视器状态异常
Java 线程同步技术 接口Lock 同步方法 同步代码块
同步代码块----代码简化---->同步方法(同步锁 代码中无法看见)---- 即便异常也要保证对象锁能够被释放,“拿取锁+释放锁”明显可见---->接口Lock
1.同步代码块
创建任意对象 例如Object obj = new Object()
synchronized(obj){ //线程要操作的共享数据 }
public class Tickets implements Runnable{ //定义出售的票源 private int ticket = 100; private Object obj = new Object(); public void run(){ while(true){ //线程共享数据,保证安全,加入同步代码块 synchronized(obj){ //对票数判断,大于0,可以出售,变量--操作 if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } } } }
/* * 多线程并发访问同一个数据资源 * 3个线程,对一个票资源,出售 */ public class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类对象 Tickets t = new Tickets(); //创建3个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start();t1.start();t2.start(); } }
2.同步方法
将同步代码块中的内容抽取到一个方法中
并在该方法的声明上,加入同步关键字 synchronized同步方法 虽然代码上无法看到“对象锁”,但实质该锁是存在的,通常该锁是本类对象引用 this;如果同步方法是静态方法 ,即被static修饰 ,则该锁不再是 本类对象this,而是类 本类自己.class 属性
public class Tickets implements Runnable{ //定义出售的票源 private int ticket = 100; public void run(){ while(true){ payTicket(); } } /*public void payTicket(){ synchronized(this){ if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } }*/ public synchronized void payTicket(){ if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } }
/* * * 问题: * 同步方法方法是静态的呢,同步有锁吗,绝对不是this * 锁是本类自己.class属性 */ public class Tickets implements Runnable{ //定义出售的票源 private static int ticket = 100; public void run(){ while(true){ payTicket(); } } public static void payTicket(){ synchronized(Tickets.class){ if( ticket > 0){ try{ Thread.sleep(10); }catch(Exception ex){} System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); } } } }
3.接口Lock
该接口 来自于java.util.concurrent.locks包
/* * 使用JDK1.5 的接口Lock,替换同步代码块,实现线程的安全性 * Lock接口方法: * 使用接口Lock的 实现类ReentrantLock * 先获取锁 接口Lock的lock()方法 * 最后释放锁 接口Lock的unlock()方法 * */ public class Tickets implements Runnable{ //定义出售的票源 private int ticket = 100; //在类的成员位置,创建Lock接口的实现类对象 private Lock lock = new ReentrantLock(); public void run(){ while(true){ //调用Lock接口方法lock获取锁 lock.lock(); //对票数判断,大于0,可以出售,变量--操作 if( ticket > 0){ try{ Thread.sleep(10); System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--); }catch(Exception ex){ }finally{ //释放锁,调用Lock接口方法unlock lock.unlock(); } } } } }
/* * 多线程并发访问同一个数据资源 * 3个线程,对一个票资源,出售 */ public class ThreadDemo { public static void main(String[] args) { //创建Runnable接口实现类对象 Tickets t = new Tickets(); //创建3个Thread类对象,传递Runnable接口实现类 Thread t0 = new Thread(t); Thread t1 = new Thread(t); Thread t2 = new Thread(t); t0.start();t1.start();t2.start(); } }

浙公网安备 33010602011771号