00102_线程安全和线程同步
1、线程安全
(1)如果有多个线程在同时运行,而这些线程可能会同时运行这段代码;
(2)程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的;
(3)代码演示:
①模拟票
1 public class Ticket implements Runnable { 2 // 共100票 3 int ticket = 100; 4 5 @Override 6 public void run() { 7 // 模拟卖票 8 while (true) { 9 if (ticket > 0) { 10 // 模拟选坐的操作 11 try { 12 Thread.sleep(1); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 System.out.println(Thread.currentThread().getName() + "正在卖票:" 17 + ticket--); 18 } 19 } 20 } 21 }
②测试类
1 public class ThreadDemo { 2 public static void main(String[] args) { 3 // 创建票对象 4 Ticket ticket = new Ticket(); 5 6 // 创建3个窗口 7 Thread t1 = new Thread(ticket, "窗口1"); 8 Thread t2 = new Thread(ticket, "窗口2"); 9 Thread t3 = new Thread(ticket, "窗口3"); 10 11 t1.start(); 12 t2.start(); 13 t3.start(); 14 } 15 }
③运行结果:
(4)上面程序出现了问题,错误的票0、-1;
(5)其实,线程安全问题都是由全局变量及静态变量引起的;
(6)若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;
(7)若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
2、线程同步(线程安全处理Synchronized)
(1)线程同步的方式有两种:
①同步代码块;
②同步方法
(2)同步代码块
①同步代码块: 在代码块声明上 加上synchronized
synchronized (锁对象) { 可能会产生线程安全问题的代码 }
②同步代码块中的锁对象可以是任意的对象;但多个线程时,要使用同一个锁对象才能够保证线程安全。
③使用同步代码块,对卖票案例中Ticket类进行如下代码修改,当使用了同步代码块后,上述的线程的安全问题,解决了。
1 public class Ticket implements Runnable { 2 // 共100票 3 int ticket = 100; 4 // 定义锁对象 5 Object lock = new Object(); 6 7 @Override 8 public void run() { 9 // 模拟卖票 10 while (true) { 11 // 同步代码块 12 synchronized (lock) { 13 if (ticket > 0) { 14 // 模拟电影选坐的操作 15 try { 16 Thread.sleep(10); 17 } catch (InterruptedException e) { 18 e.printStackTrace(); 19 } 20 System.out.println(Thread.currentThread().getName() 21 + "正在卖票:" + ticket--); 22 } 23 } 24 } 25 } 26 }
(3)同步方法
①同步方法:在方法声明上加上synchronized;
1 public synchronized void method(){ 2 可能会产生线程安全问题的代码 3 }
②同步方法中的锁对象是 this。
③使用同步方法,对电影院卖票案例中Ticket类进行如下代码修改,
1 public class Ticket implements Runnable { 2 //共100票 3 int ticket = 100; 4 //定义锁对象 5 Object lock = new Object(); 6 @Override 7 public void run() { 8 //模拟卖票 9 while(true){ 10 //同步方法 11 method(); 12 } 13 } 14 15 //同步方法,锁对象this 16 public synchronized void method(){ 17 if (ticket > 0) { 18 //模拟选坐的操作 19 try { 20 Thread.sleep(10); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--); 25 } 26 } 27 }
(4)静态同步方法
①静态同步方法: 在方法声明上加上static synchronized;
②静态同步方法中的锁对象是 类名.class。
public static synchronized void method(){ 可能会产生线程安全问题的代码 }
其实,线程安全问题都是由全局变量及静态变量引起的