Java运行多线程并发运行,如果多个线程执行过程中需要访问同一个资源,可能会导致资源数据不正确。
例如:有150张火车票,多个窗口同时售卖,就可能出现不同窗口卖出同一张票。
package com.wanmait.sys; public class TrainTickets implements Runnable { private int count = 150; public void run() { while(true) { if(count>0)//还有余票 { System.out.println("窗口卖"+count+"号票"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } count--; } } } }
线程同步,在一个线程访问资源没有结束之前,其他线程不能访问。
线程同步实现:
方式一
synchronized实现
任意一个对象,都有自己独立的监视器(monitor),当执行同步代码时,必须先获得该对象的监视器,然后才能执行同步代码,没有获得监视器的线程,只能等待,成为阻塞状态,等到获得监视器的线程执行完毕。
public class TrainTickets implements Runnable { private int count = 150; public void run() { while(true) { if(count>0)//还有余票 { synchronized(this) { System.out.println("窗口卖"+count+"号票"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } count--; } } } } }
方式二
ReentrantLock
锁对象,通过ReentrantLock对象获取和释放锁
lock()锁对象 unlock()方法解锁
import java.util.concurrent.locks.ReentrantLock; public class TrainTickets implements Runnable { private int count = 150; private ReentrantLock lock = new ReentrantLock(); public void run() { while(true) { if(count>0)//还有余票 { lock.lock(); System.out.println("窗口卖"+count+"号票"); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } count--; lock.unlock(); } } } }
区别:
1 ReentrantLock是类 synchronized是关键字
2 synchronized发生异常时,自动释放线程占有的锁,ReentrantLock出现异常,不会释放锁,所以需要在finally调用unlock方法释放锁
3 synchronized是非公平锁,ReentrantLock可以设置成为公平锁,让所有的线程都有执行的机会
4 synchronized是不可中断锁,ReentrantLock是可中断锁
0条评论
点击登录参与评论