线程在执行的过程中,容易出现安全问题,除了线程死锁外,所谓的安全问题就是:
对需要同步的变量进行多线程操作时,会使变量的判定发生问题,比如卖票的问题可能出现0票或者-1,-2的情况,
那么我们就需要一个锁来对需要同步的变量或者方法进行标记,指示:
该变量或方法在某个时刻或时间段只能被一个线程所执行
1 //错误代码演示: 2 public class ThreadDemo implements Runnable { 3 //创建线程的第一种方式:继承Thread类 4 private int ticket =100; 5 Object object = new Object(); 6 @Override 7 public void run() { 8 while(true) { 9 if (ticket>0) { 10 try { 11 Thread.sleep(10); 12 } catch (Exception e) {} 13 System.out.println(Thread.currentThread().getName()+"-----"+ticket--); 14 } 15 } 16 } 17 } 18 19 //正确代码演示: 20 public class ThreadDemo implements Runnable { 21 //创建线程的第一种方式:继承Thread类 22 private int ticket =100; 23 Object object = new Object(); 24 @Override 25 public void run() { 26 while(true) { 27 synchronized (object) { 28 if (ticket>0) { 29 try { 30 Thread.sleep(10); 31 } catch (Exception e) { 32 } 33 System.out.println(Thread.currentThread().getName()+"-----"+ticket--); 34 } 35 } 36 } 37 } 38 }
线程所使用的锁是有不同的,
在普通的方法或者同步代码块中:
当方法是非静态的,锁指的是调用这个方法的对象本身,也就是this;
当方法是静态的,锁指的是该方法所在类的字节码对象,也就是类名.class
演示同步代码块和同步函数的使用方法:
1 //同步代码块的使用: 2 public void run() { 3 while(true) { 4 //锁this指的是调用本方法的类实例对象 5 synchronized (this) { 6 if (ticket>0) { 7 try { 8 Thread.sleep(10); 9 //线程休眠是为了看清同步的效果,有没有产生错误的票号 10 } catch (Exception e) { 11 } 12 System.out.println(Thread.currentThread().getName()+"-----"+ticket--); 13 } 14 } 15 } 16 }
1 //同步函数的使用: 2 public class ThreadDemo implements Runnable { 3 private int ticket =100; 4 @Override 5 public void run() { 6 while(true) { 7 synchMethod(); 8 } 9 } 10 public synchronized void synchMethod() { 11 if (ticket>0) { 12 try { 13 Thread.sleep(10); 14 //线程休眠是为了看清同步的效果,有没有产生错误的票号 15 } catch (Exception e) { 16 } 17 System.out.println(Thread.currentThread().getName()+"-----"+ticket--); 18 } 19 } 20 } 21 22 //当同步的方法是静态的时候,锁使用的是本类的字节码对象:类名.class 23 public class ThreadDemo implements Runnable { 24 //这时候静态方法使用的变量也要是静态的 25 private static int ticket =100; 26 @Override 27 public void run() { 28 while(true) { 29 synchMethod(); 30 } 31 } 32 public static synchronized void synchMethod() { 33 if (ticket>0) { 34 try { 35 Thread.sleep(10); 36 //线程休眠是为了看清同步的效果,有没有产生错误的票号 37 } catch (Exception e) { 38 } 39 System.out.println(Thread.currentThread().getName()+"-----"+ticket--); 40 } 41 } 42 }