多线程安全
什么是线程安全问题
当多个线程共享同一个成员变量或者静态变量 . 做写的操作肯定会收到其他线程的干扰,导致数据有问题这种现象叫做线程安全问题(做读的操作不会发生数据冲突问题)
示例 :
1 class threadTrain1 implements Runnable { 2 3 // 重写run()方法 4 private static int count = 100; 5 6 public void run() { 7 while (count > 0) { 8 try { 9 Thread.sleep(50); 10 } catch (Exception e) { 11 e.printStackTrace(); 12 } 13 sale(); 14 } 15 } 16 17 public void sale() { 18 19 if (count > 0) { 20 System.out.println(Thread.currentThread().getName() + " 出售 第 " + (100 - count + 1) + " 张票"); 21 count--; 22 } 23 24 25 } 26 27 } 28 29 public class thread_dame_1 { 30 31 public static void main(String[] args) { 32 33 threadTrain1 thread1 = new threadTrain1(); 34 Thread t1 = new Thread(thread1, " 一号窗口 "); 35 Thread t2 = new Thread(thread1, " 二号窗口 "); 36 37 t1.start(); 38 t2.start(); 39 40 } 41 42 }
结果 :
部分票重复出售
多个线程共享同一个成员变量时会发生数据冲突
解决线程安全问题
使用多线程之间同步 synchronized 或使用锁 (lock) 解决线程安全
什么地方需要加锁
线程同步保证只有一个线程进行访问
必须要有2个线程以上,需要发生同步
当多个线程想同步时必须用同一把锁,线程同步共享一个资源不会受到其他线程的干扰
同步代码
synchronized(同一个对象(锁))//这个对象可以为任意对象 可以使用 this 锁
{ //可能发生线程冲突问题代码 }
示例 :
1 public void sale() { 2 synchronized (this) { 3 if (count > 0) { 4 System.out.println(Thread.currentThread().getName() + " 出售 第 " + (100 - count + 1) + " 张票"); 5 count--; 6 } 7 } 8 9 }
或者 :
( 修饰在方法上 为 同步函数 )
1 public synchronized void sale() {
2 if (count > 0) {
3 System.out.println(Thread.currentThread().getName() + " 出售 第 " + (100 - count + 1) + " 张票");
4 count--;
5 }
6 }
结果 :
静态同步函数
静态同步函数被 static 修饰的同步函数
静态不能用 this 静态同步函数使用的锁是 该静态函数所属的 字节码
字节码可以使用 getClass()方法获取 或者 直接 类名.class 表示
示例 :
1 public static void sale() { 2 synchronized (threadTrain1.class) { 3 if (count > 0) { 4 System.out.println(Thread.currentThread().getName() + " 出售 第 " + (100 - count + 1) + " 张票"); 5 count--; 6 } 7 } 8 }
多线程三大特性
原子性 , 可见性 , 有序性
原子性 : 保证数据一致, 保证线程安全
可见性 : 多个线程访问同一个变量时 , 一个线程修改了值 , 其他线程能立即得到修改的值,若2个线程不在同一个cpu , 那么线程a 改变了值 , b线程使用还是原来的值 , a 修改的值 b 没有看到 这就是可见性
有序性 : 程序执行的顺序按照先后顺序执行 如之前的 join()