精华内容
下载资源
问答
  • 多线程调用static方法线程安全问题

    千次阅读 2021-11-10 15:44:42
    最近在工作中遇到了线程安全的问题,是在一个方法中调用了静态方法解析Date的字符串。 因为 SimpleDateFormat这个类是线程安全的,所以不能在静态方法中定义全局的成员变量。 @Test void contextLoads() { ...

    最近在工作中遇到了线程安全的问题,是在一个方法中调用了静态方法解析Date的字符串。

    因为 SimpleDateFormat这个类是线程不安全的,所以不能在静态方法中定义全局的成员变量。

    @Test
    void contextLoads() {
        ExecutorService executorService= Executors.newFixedThreadPool(6);
        for (int i = 0; i < 6; i++) {
            Runnable runnable=new Runnable() {
                @Override
                public void run() {
                    Date date= DateUtil.ParseDate("20210501");
                    System.out.println("子线程"+Thread.currentThread().getName()+date);
                }
            };
            executorService.execute(runnable);
        }
      
    }

     

     解决方法:

    1.使用synchronized来保证线程安全。

    2.把全局变量换为使用成员变量。

    public class DateUtil {
        private static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
    //    public static synchronized   Date ParseDate(String str){
        public static  Date ParseDate(String str){
            try {
                SimpleDateFormat sf = new SimpleDateFormat("yyyyMMdd");
                return sf.parse(str);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    展开全文
  • JavaFX 中使用多线程保证 UI 线程安全JavaFX 中使用多线程JavaFX 中保证 UI 线程安全总结与补充   JavaFX 中的 UI 和大多数其它的编程语言一样,是单线程的。前人很早就已经多次尝试在 UI 上使用多线程,大多都...

    JavaFX 中使用多线程与保证 UI 线程安全

      JavaFX 中的 UI 线程和大多数其它的编程语言一样,是单线程的。前人很早就已经多次尝试在 UI 线程上使用多线程,大多都已失败告终。为保证 UI 界面的流畅,UI 线程不能执行非常耗时的操作。如果 UI 线程执行正在非常耗时的操作,这个后果在 UI 界面的体现就是,UI 界面会一直停滞在执行耗时代码前的状态,然后如果马上随意连续点击 UI 界面的任何部位,此时会发生如下现象:

    • 应用的标题会加上 (未响应) 的后缀。

    • 应用的关闭按钮会变红。

    • 光标位于此应用中时,光标会变成加载的圆圈图样。

    • 操作系统会将此应用的界面变成灰色,然后弹窗提示此程序已停止响应。

      上面的就是俗称应用卡死的状态。通过上面的描述应该可以明白,不是说一旦进入卡死的状态,就只能手动强制结束这个应用。应用卡死的状态只能一种 UI 界面被阻塞的状态(UI 界面无法自主更新)。当发生了这个状态,并不能说明程序就发生了死锁,因此此时如果等待,程序就有可能自主走出这个状态。只能说这个应用的开发者的设计不合理,UI 线程不应该执行非常耗时的操作。那么,非常耗时的操作应该在哪里执行呢?


    【注意】

      UI 界面的更新是以异步的方式进行。UI 线程首先会执行用户代码,然后如果这些代码使得 UI 界面的数据发生的改变,UI 线程将对其 UI 界面进行更新。这意味着,并不是每执行一条更改 UI 数据的代码,它都会在 UI 界面上马上生效。有时候,这会导致一些问题。

      UI 线程是单线程的,指的 UI 界面是只通过一个线程来完成它界面的更新,指的不是凡是涉及 UI 的程序只能使用一个线程。UI 应用相比于后台应用,只是多了几个与处理 UI 相关的线程而已,没什么额外的线程个数限制。

      如果想了解更多关于同步、异步、阻塞的知识,可见笔者的另一篇博客:同步阻塞、同步非阻塞、异步阻塞、异步非阻塞:https://blog.csdn.net/wangpaiblog/article/details/117236684


    JavaFX 中使用多线程

      为防止 UI 界面被阻塞,又因为 UI 线程是单线程的,因此应该选择在其它线程执行非常耗时的操作。可以选择当需要执行非常耗时的操作时,新开一个线程,将此非常耗时的操作放到新开一个线程去执行。

      在 JavaFX 中使用多线程一般使用两个类:ExecutorServiceTask<Integer>Task<Integer> 有一个方法 call,可以在这个方法去执行耗时操作。具体代码如下:

    // 假设方法 someJavafxFun 位于 JavaFX 的某个组件的定义中
    public void someJavafxFun() {
        ExecutorService executor = Executors.newCachedThreadPool();
        Task<Integer> task = new Task<>() {
            @Override
            protected Integer call() {
                // TODO 执行耗时操作
                return null; // 如果需要结果反馈,可以在此处提供反馈值
            }
        };
        /**
         * 如果不需要结果反馈,也可以直接使用 executor.execute(task);
         * 
         * 可以使用 result.get() 来获取上面的反馈值。但这个方法是同步阻塞的
         */
        var result = executor.submit(task);
    
        /**
         * 方法 getWindow() 获得的其实是 Stage。此段代码是用于在应用关闭时回收资源。
         * 
         * 对于真正的程序,方法 setOnCloseRequest 要设置在 Stage 被创建处。
         * 因为方法 setOnCloseRequest 会覆盖其它 setOnCloseRequest 的效果,所以此方法只能执行一次。
         * 为了达到这个效果,需要将 task 与 executor 设置成全局的,或者将其封装在一个全局静态方法中
         */
        this.getScene().getWindow().setOnCloseRequest(event -> {
            if (task != null) {
                task.cancel();
            }
            if (executor != null) {
                executor.shutdown();
            }
            Platform.exit();
        });
    }
    

      Task<T> 是 JavaFX 的一个类,它继承至 FutureTask<T>。而 FutureTask<T>ExecutorService 均为原生的 Java 多线程中的类,后续的操作均可依照 Java 多线程理论中的流程来完成。


    【附】

      可以使用 Thread.currentThread().getName() 来查看某代码位于的线程。如下。其中,JavaFX 的 UI 界面所在的线程名为 JavaFX Application Thread

    System.out.println("【编号xxx】 执行本代码 XXX 的线程是:" + Thread.currentThread().getName());
    

    JavaFX 中保证 UI 线程安全

      JavaFX 中的 UI 和大多数其它的编程语言中的一样,不是线程安全的,因为它是单线程的。在单线程中无需考虑线程安全的问题,但在多线程中需要考虑。介于本文讨论的重点,这里不打算解释什么是线程安全。那么,如果在 JavaFX 中使用了多线程,如何保证 UI 线程安全呢?

      在 JavaFX 中,可以在 UI 之外的线程中,使用方法 Platform.runLater 来执行与 UI 直接相关的操作。如下:

    Platform.runLater(() -> {/* // TODO 更新 UI 数据的代码 */});
    

      注意:为保证 UI 界面的流畅,只需将与 UI 直接相关的代码置入上述的方法 Platform.runLater 中,不要在此方法中放多余的代码,否则就失去了使用多线程的意义。

    总结与补充

    • 为保证 UI 界面的流畅,需要将某些代码放入新建线程中,这些代码需要同时满足以下条件:

      • 非常耗时或执行时间不能保证最坏结果也符合要求

      • 与操作 UI 数据不直接相关

      • 并非与 UI 数据强同步。

        例如:如果 UI 需要请求一个资源,如果该资源不能获得,UI 就会崩溃,那么获取该资源的代码不能放在新建线程中,除非可以保证此线程与 UI 线程可以同步。因为,在不使用任何机制的情况下,新建的线程都是非阻塞的,如果选择将获取该资源的代码放在新建线程中,在这种情况下,UI 中请求资源的方法会立即返回,这个时候获取到的是这个资源的初始值(一般是 null)。也就是说,如果选择将获取该资源的代码放在新建线程中,相当于直接注释掉了新建线程获取资源这部分的代码。

    • 为保证 UI 的线程安全,在其它线程不能直接更改 UI 的数据,必须将更改 UI 数据的代码传于方法 Platform.runLater 中运行。

    展开全文
  • 简单讨论一下在一个类中使用静态字段(static field)和静态方法(static method)是否会有线程安全问题。我们在知道, 静态字段(static field)和静态方法(static method)的调用是通过类来调用。静态方法不对特...

    类的成员分为两类,静态成员(static member)和实例成员(instance member)。静态成员属于类,实例成员则属于对象,即类的实例。

    简单讨论一下在一个类中使用静态字段(static field)和静态方法(static method)是否会有线程安全问题。

    我们在知道, 静态字段(static field)和静态方法(static method)的调用是通过类来调用。静态方法不对特定的实例操作,只能访问静态成员。实例方法可对特定的实例操作,既能访问静态成员,也能访问实例成员。

    那么,在多线程中使用静态方法是否有线程安全问题?这要看静态方法是是引起线程安全问题要看在静态方法中是否使用了静态成员。

    因为,在多线程中使用同一个静态方法时,每个线程使用各自的实例字段(instance field)的副本,而共享一个静态字段(static

    field)。所以说,如果该静态方法不去操作一个静态成员,只在方法内部使用实例字段(instance

    field),不会引起安全性问题。但是,如果该静态方法操作了一个静态字段,则需要静态方法中采用互斥访问的方式进行安全处理。

    举个简单的例子,我们使用的Console.WriteLine();中WriteLine()是Console.WriteLine类的静态方法。

    对于ASP.NET, 多个客户端访问服务器端, 这是一个多线程的例子.只要理解了原因,我们可以在三层架构中的数据访问层中放心使用静态方法(static method)来访问数据库.

    先看一个类:public class

    Test

    {

    public static String

    hello(String str)

    {

    String tmp = "";

    tmp = tmp +

    str;

    return tmp;

    }

    }

    hello方法会不会有多线程安全问题呢?没有!静态方法如果没有使用静态变量,则没有线程安全问题。

    为什么呢?因为静态方法内声明的变量,每个线程调用时,都会新创建一份,而不会共用一个存储单元。比如这里的tmp,每个线程都会创建自己的一份,因此不会有线程安全问题。

    注意:静态变量,由于是在类加载时占用一个存储区,每个线程都是共用这个存储区的,所以如果在静态方法里使用了静态变量,这就会有线程安全问题!

    展开全文
  • [我的公众号](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190606104746.png)## 什么是线程安全?![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610101014.png)## volatile ...

    欢迎关注我的公众号:

    ![我的公众号](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190606104746.png)

    ## 什么是线程安全?

    ![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20190610101014.png)

    ## volatile 关键字

    保证了有序性,可见性,但是没保证原子性。

    由于java的内存模型的原因,线程在修改了共享变量后并不会立即把修改同步到内存中,而是会保存到线程的本地缓存中。

    **volatile关键字修饰的变量在线程修改后会立刻同步到主内存中,使该修改对其他线程可见**

    ## Synchronized 关键字

    * sychronized 是java中的内置锁,可以限制线程对代码块或者方法的访问

    * sychronized可以修饰类方法,实例方法,代码块

    * 在执行sychronized方法或代码块时,线程需要先获取被修饰对象的锁。一次只能有一个线程可以获取到一个对象的锁,同一个线程可以多次获取同一个对象的锁(可重入锁)

    * sychronized 不能响应中断,当一个线程在等待锁的时候,调用该线程的interrupt是不起作用的

    * 锁的获取和释放是隐式的,进入同步sychronized blocks后会获取锁,离开sychronized blocks后会释放锁

    ## Obejct类的wait/notify方法

    * wait/notify是用于线程同步的方法

    * wait方法会使得当前线程放弃调用对象的监控,并使当前线程进入等待。直到调用了该对象的notify方法或者notifyAll方法(语法上是这样设计,但存在例外)

    * 可以多次调用对象的wait方法,notify方法只会随机释放一个wait方法等待,与调用顺序无关。如果要释放所有的wait调用可以调用notifyAll方法

    * 调用wait的线程有可能会存在interrupt,虚假唤醒的情况,导致wait方法返回,但实际并没有调用对象的notify方法。在使用时通常会搭配一个lock flag和loop使用

    ## ThreadLocal 实现

    ThreadLocal实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程。ThreadLocal是一个线程级别的局部变量,下面是线程局部变量(ThreadLocal variables)的关键点:

    1. 当使用ThreadLocal维护变量时,若多个线程访问ThreadLocal实例,ThreadLocal为每个使用该变量的线程提供了一个独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其他线程所对应的副本。

    2. 从线程的角度看,目标变量就像是线程的本地变量,这也是类名中Local所要表达的意思。

    首先:ThreadLocal 是一个泛型类,内部有个静态内部类 ThreadLocalMap,使用弱引用的方式保存 ThreadLocal。

    在每个线程内部有一个`ThreadLocal.ThreadLocalMap threadLocals = null;`, 这个 map 的 key 就是每个线程的实例.

    在 get 或者 put 的时候,会先通过 getMap 拿当前线程绑定的 ThreadLocalMap 对象,如果没有,会创建一个新的对象。以 ThreadLocal 为 key,以泛型为 value。

    这样,在访问 ThreadLocal 类的时候,都会通过拿其内部的 ThreadLocalMap,然后再去获得设置的泛型值。

    所以就导致,不同的类在内部设置 ThreadLocalMap 以后,确保能够保证同个线程中值是唯一的。

    [参考地址](https://www.cnblogs.com/studyLog-share/p/5295557.html)

    ## 重入锁实现线程同步

    Lock,一般使用其实现类 ReentrantLock。

    ReentrantLock获取锁定与三种方式:

    1. lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁

    2. tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;

    3. tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;

    4. lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断

    ReentrantLock 和 Synchronized 的区别:

    线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,

    - 如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断

    - 如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情

    展开全文
  • 之前在看一些模拟面试的视频时,面试官问到:“List如何保证线程安全“。我脑海中首先想到的是使用List接口下的Vector集合。然后面试者也同样简单的说出使用Vector集合。但是面试官显然对这个回答并不满意。那么List...
  • 在Java中可以有很多方法保证线程安全,比如使用同步方法、同步块,使用原子类(atomic concurrent classes),实现并发锁,使用volatile关键字,使用不变类和线程安全类。这里是最基础的线程安全教程实际上在...
  • 众所周知,多线程会造成线程安全问题,那么多线程为什么会导致线程安全问题呢? 一:首先了解jvm内存的运行时数据区 1.堆区:存储对象实例(和实例变量),数组等 2.java虚拟机栈(方法·栈),存放方法声明,...
  • 通过前面两章的学习,我们了解了线程的基本概念和创建线程的四种方式,今天,我们来谈谈线程安全问题。 也许你刚听到这个词语的时候,是一脸懵逼,笔者初学线程安全也是这样的。所以本章从几个案例入手,让小伙伴...
  • } } } 上面是我对静态变量的线程安全方案,就是在设置值的时候开启一个线程同步锁的机制,不知道这样是否有效,我在测试的时候,程序死锁过。 请问有什么有效的方法可以测试吗或者解决我当前的问题,谢谢!
  • 这时为保证线程安全,需要加synchronized。 他的不安全在于,虽然官方帮你加上了同步锁,保证同一时间只会又一个线程操作同一个方法,但是他不能控制个线程同时操作方法,也就是说,删除和添加是可以同时进行...
  • 多线程 yield 方法

    2020-12-22 11:22:32
    多线程 yield 方法 1. 前言 本节对 yield 方法进行深入的剖析,主要内容点如下: 首先要了解什么是 CPU 执行权,因为 yield 方法与 CPU 执行权息息相关; 了解 yield 方法的作用,要明确 yield 方法的使用所带来的...
  • 1、多线程的创建注意:线程开启不一定立即执行,由CPU调度执行1.1创建方式一继承Thread类,重写run()方法,调用start()方法开启线程。package SunThread;public class Thread_01 extends Thread{@Overridepublic ...
  • 什么是线程安全 在《Java并发编程实战》中,定义如下: 当个线程访问某各类时,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在调用代码中不...保证线程安全的手段有哪些 线程封闭 实现好的并
  • 先说结论:main方法启动后,jvm会开启个守护线程,但main方法中的代码是被单线程执行的。 上代码: 下面这段代码通过java提供的线程管理类ThreadMXBean中的dumpAllThreads方法返回所有活动线程线程信息,并打印...
  • Java多线程,线程安全,线程死锁,线程通信,线程同步(上) 什么是线程?? 线程是计算机执行的最小单位,在一个进程中可以有多个不同线程 多线程有什么用?干什么的? 单线程就像一个瓶子戳一个洞,而多线程是戳了多个洞,...
  • Copy On Write 也是一种重要的思想,在写少读的场景下,为了保证集合的线程安全性,我们完全可以在当前线程中得到原始数据的一份拷贝,然后进行操作。JDK集合框架中为我们提供了 ArrayList 的这样一个实现:...
  • JAVA中的多线程并发运行安全问题

    千次阅读 热门讨论 2021-03-19 17:58:27
    JAVA中的多线程并发运行安全问题 1.什么是多线程并发运行安全问题? 当多个线程并发操作一个数据时,由于线程操作的时间不可控的原因,可能会导致操作该数据时的过程没有按照程序设计的执行顺序运行,导致操作后数据...
  • 多线程环境中如何保证线程安全?java可以实现线程安全的方式归纳如下:1、使用synchronized关键字synchronized关键字可以修饰方法和代码块,它的语义是保证同一段代码同一时间只能有一个线程在执行。2、使用volatile...
  • 简单讨论一下在一个类中使用静态字段(static field)和静态方法(static method)是否会有线程安全问题。我们在知道, 静态字段(static field)和静态方法(static method)的调用是通过类来调用。静态方法不对特...
  • Map线程安全的四种实现方法

    千次阅读 2021-02-12 20:22:21
    Map 线程安全四种方法:1、使用 synchronized 关键字,代码如下synchronized(anObject) {value=map.get(key);}2、使用 JDK1.5提供的锁(java.util.concurrent.locks.Lock)lock.lock();value=map.get(key);lock.unlock...
  • 线程间的通信
  • 如果一个类在多线程执行中,在不考虑运行环境的调度干预,也不需要调用代码的协调同步,仍然保证正确地运行,那么这个类就是线程安全的也就是说,多线程环境下,线程安全的类总是有正确的行为。但是这种类在实际情况...
  • 本文实例为大家分享了java多线程读取多个文件的具体代码,供大家参考,具体内容如下工具类代码如下:import java.io.*;import java.util.List;import java.util.concurrent.CountDownLatch;/*** 多线程读取多个文件*...
  • 在Java语言中,不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再采取任何的线程安全保障措施。final关键字修饰的类或数据不可修改,可靠性最高。如String类,Integer类。 二、线程...
  • Java多线程

    2021-02-28 06:03:31
    多线程应用程序的执行都是cpu在做着快速的切换完成的。这个切换是随机的1、进程直译:正在进行中的程序一个程序就是一个进程,而一个程序中的多个任务则被称为线程,进程其实就是一个静态的概念2、线程(控制单元/...
  • 假如说有两个线程,其中有一个线程对一块内存加了锁,那么另一个线程再同样访问这块内存时候就会被堵塞,一旦前一个线程暂停了,那么就凉了。...那么中断的方法一般采用interrupt或boolean标志位判断线程是否...
  • Java多线程同步解决线程安全的理解

    千次阅读 热门讨论 2021-03-02 19:03:32
    Java多线程使用同步机制处理线程安全的理解 ** ** Java中多线程的创建有三种,这里只说两种。 1.继承于Thread类 ①即创建一个Thread的子类 ②重写Thread类中的run()方法方法体中写线程执行的操作 ③通过子类的对象...
  • 并发情况下如何保证数据安全,一直都是开发人员每天都要面对的问题,稍不注意就...无状态我们都知道只有线程访问公共资源的时候,才可能出现数据安全问题,那么如果我们没有公共资源,是不是就没有这个问题呢?...
  • 线程安全与否和是否在线程中使用有关虽然你定义的是 private,但有很方法都可以在其它线程中间接的访问到它,所以它存在在线程中使用的可能,但是代码里又没有加入同步处理,所以它是不安全的。...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 664,390
精华内容 265,756
关键字:

多线程保证线程安全的方法