8.2.解决线程安全问题的三种方法
方法1:同步代码块
synchronized ( 对象){
// 需要被同步的代码;
}
class Window extends Thread{
// private int ticket=100;//这样会有300张票
private static int ticket=100;//只有100张票
// Object obj=new Object();//不能用obj,会出现3个obj
static Object obj=new Object();//用静态的
@Override
public void run() {
while(true){
synchronized (obj){//这个地方如果用this,代表t1,t2,t3
//可以用Window.class 类也是对象 只会加载一次
//Class clazz=Window.class
if(ticket>0){
System.out.println(Thread.currentThread().getName()+":卖票,票号为"+ticket);
ticket--;
}else{
break;
}
}
}
}
}
方法2:同步方法:
public synchronized void show (String name){
需要被同步代码
}
class Window2 implements Runnable{
private int ticket=100;
@Override
public void run() {
while (true){
show();
}
}
//同步方法
private synchronized void show(){//同步监视器:this
if(ticket>0){
System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
ticket--;
}
}
}
方法3:Lock( 锁)(jdk5.0出现)
class A{
private final ReentrantLock lock = new ReenTrantLock();
public void m(){
lock.lock();
try{
// 保证线程安全的代码;
}
finally{
lock.unlock();
}
}
}
class Window implements Runnable{
private int tecket=100;
private final ReentrantLock lock=new ReentrantLock();
@Override
public void run() {
while(true){
try{
lock.lock();
if(tecket>0)
{
try {//卖票慢点
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":售票,票号为:"+tecket);
tecket--;
}else{
break;
}
}finally{
lock.unlock();
}
}
}
}
synchronized 与 Lock 的对比:
1. Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放
2. Lock只有代码块锁,synchronized有代码块锁和方法锁
3. 使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)
优先使用顺序:
Lock >同步代码块(已经进入了方法体,分配了相应资源)>同步方法(在方法体之外)