看代码,看注释,
一般都是用 synchronized(this){ 代码块 }, 其中注意体会this到底代表的是谁, 并注意 加锁的代码块的范围别太小造成跑出的数据异常。
public class SynDemo01 { /** * @param args */ public static void main(String[] args) { //真实角色 Web12306 web= new Web12306(); //代理, 这两个代理都是针对 同一个真实对象 web 进行操作的,这样在 synchronized(this)的时候才会保证加锁正确。 Thread t1 =new Thread(web,"zhangsan"); Thread t2 =new Thread(web,"lisi"); //启动线程 t1.start(); t2.start(); } } /** * 线程安全的类 线程安全 需要等待 这就是效率低的说法的来源 加锁下,范围不能太大 太大效率低 太小锁不正确 , 并且加锁对象也要对,否则达不到加锁目的 * @author Administrator * */ class Web12306 implements Runnable { private int num =10; private boolean flag =true; @Override public void run() { while(flag){ test5(); } } // 加锁范围太小 造成数据异常 // 跑出结果中 有 lisi抢到了-1 public void test6(){ if(num<=0){ flag=false; //跳出循环 return ; } //a b c synchronized(this){ // try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //线程不安全 锁定资源不正确 /** lisi抢到票了,还剩下 0 张 zhagnsan抢到票了,还剩下 0 张 */ public void test5(){ //a b c synchronized((Integer)num){// 锁错对象了 一般锁定最多的还是锁对象 if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //锁定范围不正确 线程不安全 /** * zhagnsan抢到票了,还剩下 -1 张 */ public void test4(){ // c 1 synchronized(this){ //b if(num<=0){ flag=false; //跳出循环 return ; } } // b try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); }//a -->1 //线程安全 锁定正确 public void test3(){ //a b c synchronized(this){// this 表示这份资源, 只有多个线程在使用 同一个Web12306类的对象时,才会进行加锁,eg:线程1 线程2 同时操作Web12306类的对象1,这两个线程在抢夺ticket时,哪个线程先进来就加锁 if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } //线程安全 锁定正确 public synchronized void test2(){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); //模拟 延时 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } //线程不安全 /** lisi抢到票了,还剩下 0 张 zhagnsan抢到票了,还剩下 -1 张 lisi抢到票了,还剩下 -2 张 */ public void test1(){ if(num<=0){ flag=false; //跳出循环 return ; } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } }