精华内容
下载资源
问答
  • 解决线程安全问题的三种方法

    千次阅读 2019-05-29 12:13:17
    解决线程安全问题的三种方法 一、使用同步代码块 如:卖票案例 出现了线程安全 重复的票不能出现 步骤 成员位置建立锁对象; synchronized(锁对象){ 出现安全问题代码 } 1 锁对象 任意对象 2 必须保证多个线程使用的...

    解决线程安全问题的三种方法

    一、使用同步代码块

    如:卖票案例 出现了线程安全 重复的票不能出现

    步骤
    成员位置建立锁对象;
    synchronized(锁对象){
    出现安全问题代码
    }

    1 锁对象 任意对象
    2 必须保证多个线程使用的是同一个锁对象
    3 把{} 只让一个线程进

    例子:

    public class RunnableImpl implements  Runnable{
        // 定义共享资源   线程不安全
        private int ticket = 100;
        //在成员位置创建一个锁对象
        Object obj = new Object();
        // 线程任务  卖票
        @Override
        public void run() {
            while(true){
                //建立锁对象
                synchronized (obj){
                    if(ticket>0){
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //卖票操作
                        System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
                        ticket--;
                    }
                }
            }
        }
    }
    
    

    二、使用同步方法解决多线程安全

    步骤

    1 创建一个方法 修饰符添加synchronized
    2 把访问了 共享数据的代码放入到方法中
    3 调用同步方法

    例子

    public class RunnableImpl implements  Runnable{
        // 定义共享资源   线程不安全
        private int ticket = 100;
        // 线程任务  卖票
        @Override
        public void run() {
            while(true){
                payTicket();//调用下面synchronized修饰的方法
            }
        }
        public synchronized void payTicket(){
            if(ticket>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //卖票操作
                System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
                ticket--;
            }
        }
    }
    
    展开全文
  • 线程安全三种Map方法

    千次阅读 2018-04-08 11:53:15
    //创建安全线程的Mapstatic Map<Integer,User> users = Collections.synchronizedMap(new HashMap<Integer,User>());//HashtableMap<String, String> normalMap = new ...
    //创建安全线程的Map
    static Map<Integer,User> users = Collections.synchronizedMap(new HashMap<Integer,User>());
    //Hashtable
    Map<String, String> normalMap = new Hashtable<String, String>();
    展开全文
  • 确保线程安全的几种方法

    万次阅读 2017-07-10 18:12:43
    本文首先对线程进行简单的介绍,然后介绍几保证线程安全方法

    无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家。教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家。点这里可以跳转到教程。”

    对于基于Linux操作系统的开发者来说,多线程是一个在开发和面试中不可避免的、被广泛讨论的话题。最近,我被问到了一个和多线程有关的问题:如何确保线程安全?在刚听到这个问题的时候,我还一时回答不上来。后面,我查找了与线程安全相关的资料,算是补上了问题的答案。本文首先对线程进行简单的介绍,然后介绍几种保证线程安全的方法。

    线程简介
    在介绍线程之前,要引入进程(Process)的概念。进程有狭义和广义之分,狭义的进程是正在运行的程序的实例;广义的进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是操作系统动态执行的基本单元。

    线程(Thread),有时被称为轻量级进程(LWP),是程序执行流的最小单位;一个标准的线程由线程ID、当前指令指针(PC)、寄存器集合和堆栈组成。通常情况下,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间及一些进程级的资源。

    在大多数软件应用中,线程的数量都不止一个,多线程程序处在一个多变的环境中,可访问的全局变量和堆数据随时都可能被其他的线程改变,这就将“线程安全”的问题提上了议程。那么,如何确保线程的安全呢?

    线程安全
    一般说来,确保线程安全的方法有这几个:竞争与原子操作、同步与锁、可重入、过度优化

    竞争与原子操作
    多个线程同时访问和修改一个数据,可能造成很严重的后果。出现严重后果的原因是很多操作被操作系统编译为汇编代码之后不止一条指令,因此在执行的时候可能执行了一半就被调度系统打断了而去执行别的代码了。一般将单指令的操作称为原子的(Atomic),因为不管怎样,单条指令的执行是不会被打断的。

    因此,为了避免出现多线程操作数据的出现异常,Linux系统提供了一些常用操作的原子指令,确保了线程的安全。但是,它们只适用于比较简单的场合,在复杂的情况下就要选用其他的方法了。

    同步与锁
    为了避免多个线程同时读写一个数据而产生不可预料的后果,开发人员要将各个线程对同一个数据的访问同步,也就是说,在一个线程访问数据未结束的时候,其他线程不得对同一个数据进行访问。

    同步的最常用的方法是使用锁(Lock),它是一种非强制机制,每个线程在访问数据或资源之前首先试图获取锁,并在访问结束之后释放锁;在锁已经被占用的时候试图获取锁时,线程会等待,直到锁重新可用。

    二元信号量是最简单的一种锁,它只有两种状态:占用与非占用,它适合只能被唯一一个线程独占访问的资源。对于允许多个线程并发访问的资源,要使用多元信号量(简称信号量)。

    可重入
    一个函数被重入,表示这个函数没有执行完成,但由于外部因素或内部因素,又一次进入该函数执行。一个函数称为可重入的,表明该函数被重入之后不会产生任何不良后果。可重入是并发安全的强力保障,一个可重入的函数可以在多线程环境下放心使用。

    过度优化
    在很多情况下,即使我们合理地使用了锁,也不一定能够保证线程安全,因此,我们可能对代码进行过度的优化以确保线程安全。

    我们可以使用volatile关键字试图阻止过度优化,它可以做两件事:第一,阻止编译器为了提高速度将一个变量缓存到寄存器而不写回;第二,阻止编译器调整操作volatile变量的指令顺序。

    在另一种情况下,CPU的乱序执行让多线程安全保障的努力变得很困难,通常的解决办法是调用CPU提供的一条常被称作barrier的指令,它会阻止CPU将该指令之前的指令交换到barrier之后,反之亦然。

    展开全文
  • Java结束线程三种方法

    万次阅读 多人点赞 2016-10-16 18:15:08
    线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远...有三种方法可以结束线程: 1.设置退出标志,使线程正常退

    线程属于一次性消耗品,在执行完run()方法之后线程便会正常结束了,线程结束后便会销毁,不能再次start,只能重新建立新的线程对象,但有时run()方法是永远不会结束的。例如在程序中使用线程进行Socket监听请求,或是其他的需要循环处理的任务。在这种情况下,一般是将这些任务放在一个循环中,如while循环。当需要结束线程时,如何退出线程呢?

    有三种方法可以结束线程:

    • 1.设置退出标志,使线程正常退出,也就是当run()方法完成后线程终止

    • 2.使用interrupt()方法中断线程

    • 3.使用stop方法强行终止线程(不推荐使用,Thread.stop, Thread.suspend, Thread.resume 和Runtime.runFinalizersOnExit 这些终止线程运行的方法已经被废弃,使用它们是极端不安全的!)

    前两种方法都可以实现线程的正常退出;第3种方法相当于电脑断电关机一样,是不安全的方法。

    1.使用退出标志终止线程
    一般run()方法执行完,线程就会正常结束,然而,常常有些线程是伺服线程。它们需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,例如:最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出,代码示例:

    public class ThreadSafe extends Thread {
        public volatile boolean exit = false; 
            public void run() { 
            while (!exit){
                //do something
            }
        } 
    }

    定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false.在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值.

    2.使用interrupt()方法中断当前线程
    使用interrupt()方法来中断线程有两种情况:

    1.线程处于阻塞状态,如使用了sleep,同步锁的wait,socket中的receiver,accept等方法时,会使线程处于阻塞状态。当调用线程的interrupt()方法时,会抛出InterruptException异常。阻塞中的那个方法抛出这个异常,通过代码捕获该异常,然后break跳出循环状态,从而让我们有机会结束这个线程的执行。通常很多人认为只要调用interrupt方法线程就会结束,实际上是错的, 一定要先捕获InterruptedException异常之后通过break来跳出循环,才能正常结束run方法。

    代码示例:

    public class ThreadSafe extends Thread {
        public void run() { 
            while (true){
                try{
                        Thread.sleep(5*1000);//阻塞5妙
                    }catch(InterruptedException e){
                        e.printStackTrace();
                        break;//捕获到异常之后,执行break跳出循环。
                    }
            }
        } 
    }

    2.线程未处于阻塞状态,使用isInterrupted()判断线程的中断标志来退出循环。当使用interrupt()方法时,中断标志就会置true,和使用自定义的标志来控制循环是一样的道理。
    代码示例:

    public class ThreadSafe extends Thread {
        public void run() { 
            while (!isInterrupted()){
                //do something, but no throw InterruptedException
            }
        } 
    }

    为什么要区分进入阻塞状态和和非阻塞状态两种情况了,是因为当阻塞状态时,如果有interrupt()发生,系统除了会抛出InterruptedException异常外,还会调用interrupted()函数,调用时能获取到中断状态是true的状态,调用完之后会复位中断状态为false,所以异常抛出之后通过isInterrupted()是获取不到中断状态是true的状态,从而不能退出循环,因此在线程未进入阻塞的代码段时是可以通过isInterrupted()来判断中断是否发生来控制循环,在进入阻塞状态后要通过捕获异常来退出循环。因此使用interrupt()来退出线程的最好的方式应该是两种情况都要考虑:

    代码示例:

    public class ThreadSafe extends Thread {
        public void run() { 
            while (!isInterrupted()){ //非阻塞过程中通过判断中断标志来退出
                try{
                    Thread.sleep(5*1000);//阻塞过程捕获中断异常来退出
                }catch(InterruptedException e){
                    e.printStackTrace();
                    break;//捕获到异常之后,执行break跳出循环。
                }
            }
        } 
    }

    3.使用stop方法终止线程
    程序中可以直接使用thread.stop()来强行终止线程,但是stop方法是很危险的,就象突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,不安全主要是:thread.stop()调用之后,创建子线程的线程就会抛出ThreadDeatherror的错误,并且会释放子线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用thread.stop()后导致了该线程所持有的所有锁的突然释放(不可控制),那么被保护数据就有可能呈现不一致性,其他线程在使用这些被破坏的数据时,有可能导致一些很奇怪的应用程序错误。因此,并不推荐使用stop方法来终止线程。

    展开全文
  • 对于多线程编程,很多人概念不清,写代码的时候要么是处处加锁,影响性能不说,还容易莫名其妙的死锁,还有人对多线程敬而远之。C/C++: ...全局原生变量多线程读写是不安全的 全局变量是在堆(heap)中
  • 线程安全的使用HashMap的三种方法

    千次阅读 2018-10-25 20:45:33
    但是在对线程同步有要求的情况下,HashMap由于自身特性不能满足,可以采用下面几方式 1,Hashtable Map&lt;String, String&gt; map = new Hashtable&lt;&gt;() 2,ConcurrentHashMap Map&...
  • 当进程中有多个并发线程进入一个重要数据的代码块时,在修改数据的过程中,很有可能引发线程安全问题,从而造成数据异常。例如,正常逻辑下,同一个编号的火车票只能售出一次,却由于线程安全问题而被多次售出,从而...
  • java线程安全的实现方法

    千次阅读 2019-01-21 18:01:32
    java线程安全被分为了几个等级类,但不管怎样总体来讲就是使线程之内和几个线程之间的事务操作具有原子性,数据具有正确性,一般来讲具有以下几种方法 目录 1.互斥同步 2.非阻塞同步 3.无同步方案 1.互斥同步 ...
  • (注意:多线程情况下的判断,如果你能确定就两个线程(不包括main主线程或者是说...arraylist不是线程安全的他的add方法没有synchronized同步锁控制,要想实现一个线程安全的集合可以有以下三种方案: 1、使用Vecto...
  • Java线程三种停止方法

    千次阅读 2019-03-01 19:41:33
    简单来说,一个线程在运行状态中,其中断标志被设置为true之后,一旦线程调用了wait、join、sleep方法中的一,立马抛出一个InterruptedException,且中断标志被程序会自动清除,重新设置为false。...
  • MFC启动一个新线程三种方法

    千次阅读 2019-03-11 16:40:39
    转载于:... 第一AfxBeginThread() 用AfxBeginThread()函数来创建一个新线程来执行任务,工作者线程的AfxBeginThread的原型如下: CWinThread* AfxBeginThread(AFX_THREADPROC pfnThreadProc, ...
  • C++/MFC创建多线程三种方法(转载)

    万次阅读 多人点赞 2017-12-08 10:24:17
    这篇博客对多线程讲解的非常好,因此转载原文作者文章,希望对大家和自己的多线程编程能力有所...第一AfxBeginThread() 用AfxBeginThread()函数来创建一个新线程来执行任务,工作者线程的AfxBeginThread的原型如下:
  • java开启新线程三种方法: 方法1:继承Thread类 1):定义bai一个继承自Java.lang.Thread类的du类A. 2):覆盖zhiA类Thread类中的run方法。 3):我们编写需要在run方法中执行的操作:run方法中的代码,线程...
  • 一般情况下,有下面的几种方法实现这种通信任务:使用全局变量(上一节的例子其实使用的就是这种方法)、使用事件对象、使用消息。这里我们主要介绍后两种方法。    (一) 利用用户定义的消息通信    在...
  • 而Java主要提供了三种实现同步机制的方法。今天我们就来认识一下~~ 一、synchronized关键字 在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程锁拥有,当一个线...
  • Java多线程:向线程传递参数的三种方法

    万次阅读 多人点赞 2018-03-18 12:28:02
    在传统的同步开发模式下,当我们调用一个函数时,通过这个函数的参数将数据传入,并通过这个函数的返回值来返回...本文就以上原因介绍了几用于向线程传递数据的方法,在下一篇文章中将介绍从线程中返回数据的方法...
  • 当多个线程访问某个类时,不管运行时环境采用何调度方式或者这些线程将如何交替执行,并且在调用代码中不需要任何额外的同步,这个类都能表现出正确的行为,那么这个类就是线程安全的。 对于线程安全性主要从以下...
  • 线程安全:就是当多线程访问时,采用了加锁的机制;即当一个线程访问该类的某个数据时,会对这个数据进行保护,其他线程不能对其访问,直到该线程读取完之后,其他线程才可以使用。防止出现数据不一致或者数据被污染...
  • java 创建线程三种方式、创建线程池的四种方式

    万次阅读 多人点赞 2019-02-23 21:01:44
    java创建线程三种方式: 继承Thread类创建线程类 实现Runnable接口 通过Callable和Future创建线程 java创建线程池的四种方式: newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理...
  • VC启动一个新线程三种方法

    万次阅读 2015-03-14 19:53:43
    三种_beginthread() 函数原型为:intptr_t _beginthread(  void( *start_address )( void * ), //指向新线程调用的函数的起始地址  unsigned stack_size, //堆栈大小,设置0为系统默认值  void ...
  • java中线程安全的实现方法

    千次阅读 2018-08-04 10:39:08
    在多线程编程中,同步就是一个线程进入监视器(可以认为是一个只允许一个线程进入的盒子),其他线程必须等待,直到那个线程退出监视器为止。 在实现互斥同步的方式中,最常使用的就是Synchronized 关键字。 ...
  • 原创Blog,转载请注明出处 ...我的stackoverflow 前言:最近app中的日历小概率的在...研究了下,是线程安全问题。这里,就系统性的总结下线程安全这部分。 之后的博客绝大部分源码会用Swift来写了。一些资料 objc
  • 用于解决多线程安全问题的方式: 1. 同步代码块 (隐式锁) 2. 同步方法(隐式锁) 3. 同步锁 Lock( jdk 1.5 后)  注意:是一个显示锁,需要通过 lock() 方法上锁,必须通过 unlock() 方法进行释放锁 下面举一个售票...
  • 本文试图概述几种方法,程序员可用这几种方法来创建高效的线程安全类。 并发性 只有当要解决的问题需要一定程度的并发性时,程序员才会从多线程应用程序中受益。例如,如果打印队列应用程序仅支持一台打印机和...
  • 线程传递数据的三种方法

    千次阅读 2018-06-08 14:47:45
    在传统的同步开发模式下,当我们调用一个函数时,通过这个函数的参数将数据传入,并通过这个函数的返回值来返回最终...本文就以上原因介绍了几用于向线程传递数据的方法,在下一篇文章中将介绍从线程中返回数据的...
  • Java停止线程的四种方法

    千次阅读 2019-06-09 13:26:34
    一、线程停止基础知识 interrupted(): 测试当前线程是否已经中断。该方法为静态方法,调用后会返回boolean值。不过调用之后会改变线程的状态,如果是中断状态调用的,调用之后会清除线程的中断状态。 isInterrupted...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 393,477
精华内容 157,390
关键字:

线程安全三种方法