稻香村网站建设,网页版微信登陆入口,久久建筑网下载教程,中小企业网站制作方法1、为什么有线程安全问题#xff1f; 当多个线程共享同一个全局变量或静态变量#xff0c;做写的操作时#xff0c;可能会发生数据冲突问题#xff0c;也就是线程安全问题。但是做读操作是不会发生数据冲突问题。 案例#xff1a;现在有100张火车票#xff0c;有两个窗口… 1、为什么有线程安全问题 当多个线程共享同一个全局变量或静态变量做写的操作时可能会发生数据冲突问题也就是线程安全问题。但是做读操作是不会发生数据冲突问题。 案例现在有100张火车票有两个窗口同时抢火车票请使用多线程模拟抢票效果。 代码 public class NewThread1 implements Runnable{ private int trainCount 100; Override public void run() { while (trainCount0){ try { Thread.sleep(100); }catch (Exception e){ } save(); } } private void save() { if (trainCount 0) { System.out.println(Thread.currentThread().getName() ,出售第 (100 - trainCount 1) 张票); trainCount--; } } public static void main(String[] args){ NewThread1 newThread1 new NewThread1(); Thread thread1 new Thread(newThread1,①); Thread thread2 new Thread(newThread1,②); thread1.start(); thread2.start(); }} 打印结果 ......②,出售第97张票①,出售第97张票①,出售第99张票②,出售第99张票 一号窗口和二号窗口同时出售火车第九九张部分火车票会重复出售。 结论发现多个线程共享同一个全局成员变量时做写的操作可能会发生数据冲突问题。 2、线程安全解决方法 2.1、如何解决多线程之间线程安全问题 两种主流方式 内置锁使用多线程之间同步 synchronized 关键字显示锁lock锁内置锁 内置锁使用 synchronized 关键字实现synchronized 关键字有两种用法 修饰需要进行同步的方法所有访问状态变量的方法都必须进行同步此时充当锁的对象为调用同步方法的对象 同步代码块和直接使用 synchronized 修饰需要同步的方法是一样的但是锁的粒度可以更细并且充当锁的对象不一定是 this 也可以是其它对象所以使用起来更加灵活。 简而言之synchronize 分为同步方法、同步代码块。 其中同步方法又分为非静态同步方法、静态同步方法 同步方法 [非静态同步方法] private synchronized void save() { if (trainCount 0) { System.out.println(Thread.currentThread().getName() ,出售第 (100 - trainCount 1) 张票); trainCount--; }} 同步代码块 就是将可能会发生线程安全问题的代码给包括起来。synchronized(同一个数据){ 可能会发生线程冲突问题}就是同步代码块 synchronized(对象)这个对象可以为任意对象 { 需要被同步的代码 } 对象如同锁持有锁的线程可以在同步中执行; 没持有锁的线程即使获取CPU的执行权也进不去 ; 同步的前提 必须要有两个或者两个以上的线程 必须是多个线程使用同一个锁 必须保证同步中只能有一个线程在运行 同步的优缺点 好处解决了多线程的安全问题。弊端多线程需要判断锁较为消耗资源、抢锁的资源。代码 private void save() { synchronized (this){ if (trainCount 0) { System.out.println(Thread.currentThread().getName() ,出售第 (100 - trainCount 1) 张票); trainCount--; } }} 关于 Lock 锁下次再写。 2.2、为什么使用线程同步或使用锁能解决线程安全问题呢 为了避免线程不安全问题每次只让当前一个线程进行执行代码执行完成后执行释放锁操作然后才让其他线程进行执行这样就解决了线程安全问题。 2.3、什么是多线程同步 当多个线程共享同一个资源不会受到其他线程的干扰。 2.4、什么是同步方法 在方法上修饰 sybchronized 称为同步方法。 代码示例 private synchronized void save() { if (trainCount 0) { System.out.println(Thread.currentThread().getName() ,出售第 (100 - trainCount 1) 张票); trainCount--; }} 2.5、什么是静态同步函数 方法加上 static 关键字使用 synchronize 关键字修饰 或者使用 类.class 文件。 静态的同步函数使用的锁是该函数所属字节码文件对象。 可以使用 getClass 方法获取也可以用当前 类名.class 表示。 代码示例 private static void save() { synchronized (NewThread1.class){ if (trainCount 0) { System.out.println(Thread.currentThread().getName() ,出售第 (100 - trainCount 1) 张票); trainCount--; } }} 总结 synchronize 修饰方法使用锁是当前 this 锁。 synchronize 修饰静态方法使用锁是当前类的字节码文件。 3、ThreadLocal 什么是 ThreadLocal ThreadLocal 提高一个线程的局部变量访问某个线程拥有自己局部变量。 当使用ThreadLocal维护变量时ThreadLocal为每个使用该变量的线程提供独立的变量副本所以每一个线程都可以独立地改变自己的副本而不会影响其它线程所对应的副本。 ThreadLocal 的 4 个方法 void set(Object value)设置当前线程的线程局部变量的值。public Object get()该方法返回当前线程所对应的线程局部变量。public void remove()将当前线程局部变量的值删除目的是为了减少内存的占用需要指出的是当线程结束后对应该线程的局部变量将自动被垃圾回收所以显式调用该方法清除线程的局部变量并不是必须的操作但它可以加快内存回收的速度。protected Object initialValue()返回该线程局部变量的初始值该方法是一个protected的方法显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法在线程第1次调用get()或set(Object)时才执行并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。案例 创建三个线程每个线程生成自己独立序列号。 class Res{ private ThreadLocalInteger mThreadLocal new ThreadLocalInteger(){ Override protected Integer initialValue() { return 0; }; }; protected Integer getNumber() { int count mThreadLocal.get() 1; mThreadLocal.set(count); return count; };}public class ThreadDemo1 extends Thread{ private Res res; public ThreadDemo1(Res res){ this.res res; } Override public void run() { for (int i 0; i 3; i) { System.out.println(Thread.currentThread().getName(),res.getNumber()); } } public static void main(String[] args){ Res res new Res(); ThreadDemo1 threadDemo1 new ThreadDemo1(res); ThreadDemo1 threadDemo2 new ThreadDemo1(res); ThreadDemo1 threadDemo3 new ThreadDemo1(res); threadDemo1.start(); threadDemo2.start(); threadDemo3.start(); }} 4、本章总结 线程安全的两种主流方式 内置锁synchronized显示锁lock锁ThreadLocal 提高一个线程的局部变量访问某个线程拥有自己局部变量。 我创建了一个java相关的公众号用来记录自己的学习之路感兴趣的小伙伴可以关注一下微信公众号哈niceyoo