精华内容
下载资源
问答
  • 1.不用stop()终止线程什么? http://www.cnblogs.com/greta/p/5624839.html 2.守护线程相关问题 为什么? https://blog.csdn.net/u011240877/article/details/57202704

    1.不用stop()终止线程

    为什么?

    http://www.cnblogs.com/greta/p/5624839.html

    2.守护线程相关问题

    为什么?

    https://blog.csdn.net/u011240877/article/details/57202704

     

    展开全文
  • <br /> 多线程编程可能会出现很多问题,而且有时问题无法重现,或不知什么时候会重现。或测试通过,实际运行时却出现了问题。或者在不同的虚拟机和编译器上有不同的  表现。这也是一个面试常见题,这个...

       多线程编程可能会出现很多问题,而且有时问题无法重现,或不知什么时候会重现。或测试通过,实际运行时却出现了问题。或者在不同的虚拟机和编译器上有不同的

       表现。这也是一个面试常见题,这个问题很大,有很多方面,下面谈谈我的一点体会:

        1)并不是线程越多越好。

           多线程是为了A网络服务面对同时的大量客户端请求,或同时请求大量地址如网络爬虫 

                 B,涉及GUI的图形界面编程,可以提高响应速度

                 C充分利用多核CPU的特点,提高程序执行的效率。

           一般也要十几个到几十个,具体情况具体分析

        2)正确同步访问共享的易变数据

             关于同步synchronized的两种作用A访问串行化,使可变对象在被外界观测时一直处于一种一致性的状态,否则不可访问(mutual exclusion)

                      B使一个线程对它的修改对于其他线程是可见的(communication effects)

             除long和double外的所有基本类型,或对象的引用的读写都是原子的。这保证了A,但没有保证B,所以需要volatile关键字

             (the volatile modifier performs no mutual exclusion, it

                      guarantees that any thread that reads the field will see the most recently written value)

     

                       自增运算不是原子的。the increment operator (++) is not atomic

     

                       可以共享不变对象就不会产生这样的问题。(effectively immutable,safe publication)

     

                       总结,当一些线程共享可变数据时,每个线程的读写这个数据的方法都必须显示的使用同步

                       In summary, when multiple threads share mutable data, each thread that

              reads or writes the data must perform synchronization

        3)避免过分同步

             过分同步可能会引起性能降低,死锁,甚至非确定性的行为( nondeterministic behavior.)

                      (A)To avoid liveness and safety failures, never cede control to the client within a synchronized method or block

                         换句话说,在同步区域,不要调用被设计为Override的方法,或客户端提供的 function object。

                       (B)在同步方法中要尽可能做更少的事 As a rule, you should do as little work as possible inside synchronized regions.

                          如果一个可变类是被用于多线程共享访问,你应该使它线程安全。因为内部同步比锁住整个对象的效率要高得多

                         (You should make a mutable class thread-safe (Item 70) if it is intended for

                concurrent use and you can achieve significantly higher concurrency by synchro-

                nizing internally than you could by locking the entire object externally)

               如果不是这样,就不应该使用同步。就如同StringBuffer一样,现在它被StringBuilder替代了

              In summary, to avoid deadlock and data corruption, never call an alien method

               from within a synchronized region. More generally, try to limit the amount of

               work that you do from within synchronized regions. When you are designing a

               mutable class, think about whether it should do its own synchronization. In the

               modern multicore era, it is more important than ever not to synchronize exces-

               sively. Synchronize your class internally only  if there is a good reason to do so,

               and document your decision clearly

        4)Prefer executors and tasks to threads

     

               ExecutorService executor = Executors.newSingleThreadExecutor();

                executor.execute(runnable);

                executor.shutdown();

     

             java.util.concurrent.Executors 的工厂方法提供了大多数情况下你所需要的Executor,如果你想要定制一个,那么直接使用ThreadPoolExecutor。

     

                       ScheduledThreadPoolExecutor

     

                In essence, the Executor Framework does for execution what the Collections Framework did for aggregation. 

        5)Prefer concurrency utilities to wait and notify

        6)Use lazy initialization judiciously

             7)Don’t depend on the thread scheduler

             8)Avoid thread groups

    展开全文
  • 没有官方的定义,一般来讲,当线程去访问共享的资源时,资源仍然能被正确的写入和读取,那就是线程安全的。 那什么是正确呢?一般来讲,线程自己改写的时候,要能保证操作的原子性;而且写成功了以后,要...

    一些心得,关于线程安全。

    首先什么是线程安全?

    没有官方的定义,一般来讲,当多个线程去访问共享的资源时,资源仍然能被正确的写入和读取,那就是线程安全的。

    那什么是正确呢?一般来讲,多个线程自己改写的时候,要能保证操作的原子性;而且写成功了以后,要保证资源的可见性,即能马上让别的线程看到结果。

     

    那平时写代码的时候,哪些代码容易有线程安全的问题呢?哪些代码又绝对不会有线程安全问题,不用去关注线程安全呢?

    大家知道方法是在一个线程里被执行的,也就是方法的执行环境要入某个线程的栈帧的,线程和线程的栈之间是不能互相访问的。

    那么就可以推导出,线程的局部变量是在方法中创建的,它只会属于这个栈,不会被别的线程访问到,所以方法的局部变量是线程安全的,不需要考虑线程安全的。

    那么相反的,不在方法里创建的变量,也即类的成员变量,是可以被不同的线程同时访问的,这些资源就有线程安全的隐患。

     

    那么平时写代码的时候,有什么好习惯能避免出现线程安全的问题呢?

    1 一些成员变量,如果一旦初始就不会更改,那么这些成员变量最好是声明为final的。

    2 对于类的一些成员变量是别的类的对象的,别的那些类最好也声明为final成员变量

    3 如果实在不方便声明为final成员变量,那么最好不要提供set,甚至get方法,这样就不会暴露这个数据,不提供更改的机会。

    4 大多数变量都是读比写多,如果要求可见性比较高的话,可以声明为volatile的。但是注意,volatile会每次把更改的数据立即写回主存,这对效率是有影响的,所以要酌情使用。

    5 一些工具类,本身不存储数据,没有成员变量,是无状态的,不存在线程安全问题

    6 对于一系列的操作,如果需要原子性,可以通过加锁去做

    7 对于可能有多线程操作的基本类型数据,多使用Atomic类去做

    8 如果是自己声明的类,没有Atomic类可以辅助,可以通过不断自旋的去用AtomicReference的compareAndSwap去做.

     

    以上。

     

    展开全文
  • 多线程---线程安全

    2019-11-09 17:15:42
    线程安全是开发者在开发多线程任务时最关心的问题,那么线程安全需要注意哪些呢? 一、思考:线程安全产生的原因是什么? 二、final,volatile关键字的作用? 三、1.5之前的javaDCL有什么缺陷? 四、如何编写线程...

    线程安全是开发者在开发多线程任务时最关心的问题,那么线程安全需要注意哪些呢?

    一、思考:线程安全产生的原因是什么?
    二、final,volatile关键字的作用?
    三、1.5之前的javaDCL有什么缺陷?
    四、如何编写线程安全的程序?
    五、ThreadLocal使用的注意事项有哪些?

    一、思考:线程安全产生的原因是什么?

    原因:可变资源(内存)线程间共享

    由Java的内存模型:各线程都有自己的工作内存 和 虚拟机的主内存。
    工作内存中保存了该线程使用的变量的副本,各线程对变量的所有操作必须在工作内存中进行,即操作的是变量的副本。

    看下面这个过程:
    例如:对于 int a = 3; 线程A、B、C 都要操作变量a++;

    • 当线程A操作a++后:主内存 a=3,A的工作内存 a = 4; B工作内存中 a=3; C 中 a=3;
    • 然后B也操作a++: 主内存 a=3,A的工作内存 a = 4; B工作内存中 a=4; C 中 a=3;
    • 然后A工作内存中的a同步到主内存:主内存 a=4,A的工作内存 a = 4; B工作内存中 a=4; C 中 a=3;
    • 然后主内存同步到其他线程:主内存 a=4,A的工作内存 a = 4; B工作内存中 a=4; C 中 a=4;

    这时就出问题了:a = 5才对,因为A,B线程都执行了a++,两次a++。

    二、如何实现线程安全呢?

    根据线程安全原因:可变资源(内存)线程间共享可得出:

    • 不共享资源
    • 共享不可变资源
    • 共享可变资源(可见性、操作原子性、禁止重排序)

    1、不共享资源

    ThreadLocal:

    如何使用ThreadLocal(看Loop.java中如何使用):

       
       static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
       private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
        
       public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    ThreadLocal原理:
    ThreadLocal.java

    public void set(T value) {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);
            else
                createMap(t, value);
        }
    
    //这个map是绑定在线程上的    
    ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    

    在这里插入图片描述
    ThreadLocal使用建议:

    • 声明为全局静态final成员,ThreadLocal在一个线程里有一个就够了,没必要每次初始化都创建一个。另外ThreadLocalMap是以ThreadLocal的引用为key,如果引用经常变的话,map中就匹配不到了。
    • 避免存储大量对象,由底层数据结构决定。
    • 用完后及时移除对象,如果线程一直存在,这个引用就一直不会被移除。

    final的禁止重排序:

    在这里插入图片描述
    在这里插入图片描述
    y不是final的,会被重排序,如果被重排序到构造函数之外,就会出现上面情况。

    volatile的禁止重排序:

    在JDK1.5的时候volatile的语义被增强了,增加了【禁止指令重排序】,JDK1.4之前下面的DCL单例是有问题的。

    public class Singleton {
        private static volatile Singleton singleton;  //volatile很关键
        private Singleton() {}
        public static Singleton getInstance() {
            if (null == singleton) {           //提高程序的效率
                synchronized (Singleton.class) {
                    if (null == singleton) {   //解决多线程下的安全性问题,也就是保证对象的唯一
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }
    

    jdk1.5之后的翻译为机器码指令是下面:

    1test(single == null)
    2、lock
    3test(single == null)
    4、$instance = <allocate memory>  //分配内存
    5、call constructor
    6、singleton = $instance
    7、unlock
    

    而jdk1.4之前加volatile或者jdk1.5后不加volatile的指令可能是下面:

    1test(single == null)
    2、lock
    3test(single == null)
    4、$instance = <allocate memory>  //分配内存
    5、singleton = $instance
    6、unlock
    7、call constructor
    

    结论:这样的指令造成构造函数的调用在锁外面了,当多线程时,其他线程得到锁并且判断单例不null,直接来用,但是可能这个单例并没有被构造完成,会造成不可预知的问题。

    保证可见性的方法

    1. 使用final关键字
    2. 使用volatile关键字
    3. 加锁,锁释放时会强制将工作内存刷新至主内存。
      对于3的解释:由【Happens-before规则第一条:内置锁的释放锁操作发生在该锁随后的加锁操作之前】
    原子性:

    例如a++,其实际代码如下,被拆分成了3行代码,不是原子操作。

    int tmp = a;
    tmp += 1;
    a = tmp; 
    

    保证原子性的方法:
    1、加锁,保证操作的互斥性
    2、使用CAS指令(如,Unsafe.compareAndSwapInt)
    3、使用原子数值类型(如,AtomicInteger)
    4、使用原子属性更新器(AtoicReferenceFieldUpdater)

    结论:如何编写线程安全的程序
    1. 不变性,能不共享就不共享,写可重入函数(见补充)
    2. 可见性,如果必须要共享,保证变量的可见性
    3. 原子性,保证操作的原子性
    4. 禁止指令重排序,保证代码执行的顺序

    补充:
    可重入函数,不涉及其他内存:

    public static int add(int a){
         return a + 2;
    }
    
    展开全文
  • 本文主要介绍了AsyncTask, HandlerThread, IntentService与ThreadPool分别适合的...但是编写多线程并发的代码一直以来是一个相对棘手的问题。 为主线程减轻负担的多线程方案有哪些?这些方案分别适合在什么场景下使用?
  • 没有什么可以阻止您在Swing中使用标准的多线程技术,并且需要遵循通常的注意事项。 如果您有多个线程访问相同的变量,则需要使用同步方法或代码块(或诸如AtomicInteger或ArrayBlockingQueue之类的线程安全类)。 ...
  • 没有什么可以阻止您在Swing中使用标准的多线程技术,并且需要遵循通常的注意事项。 如果有多个线程访问相同的变量,则需要使用同步方法或代码块(或诸如AtomicInteger或ArrayBlockingQueue之类的线程安全类)。 ...
  • 线程死锁

    2017-03-11 13:31:00
    编写多线程的时候,必须要注意资源的使用问题,如果两个或多个线程分别拥有不同的资源, 而同时又需要对方释放资源才能继续运行时,就会发生死锁。 简单来说:死锁就是当一个或多个进程都在等待系统资源,而...
  • 多进程程序的编写相比较多线程编写更加复杂,需要考虑进程回收、同步、互斥、通信等问题。对于初学者来说,处理上述问题会比较困难。 尤其是信号处理和进程通信这块,很难做到不出问题。 SimpleFork提供一套类似于...
  • 编写多线程的时候,必须要注意资源的使用问题,如果两个或多个线程分别拥有不同的资源, 而同时又需要对方释放资源才能继续运行时,就会发生死锁。 简单来说:死锁就是当一个或多个进程都在等待系统资源,而...
  • 全称是Grand Central ...GCD会自动利用更的CPU内核(比如双核、四核),GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程),程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码。...
  • 那么我们在编写代码的过程中,需要注意哪些线程安全的问题呢?一起来看看吧。大家都做过方法重写,我们知道方法重写是不会检查方法修饰符的,也就是说,我们可以将一个synchronized的方法重写成为非线程安全的方法:...
  • 在进行并发编程时,如果希望程序运行的更快,则需要注意线程的上下文切换问题、死锁问题、以及硬件和软件现在的问题,只有在考虑到这些问题时,我们才能用好并发编程,编写出快的并发代码。 一 ,上下切换问题  ...
  • 您应该显示一个加载指示器(但要注意使它永远旋转的竞赛条件),显示用户友好的错误(但不是多余的-没有模态警报犬!),为用户提供重试机制……并在发生时隐藏所有这些信息后续请求成功。 确保避免冗余请求和冗余...
  • 什么说i++不是原子操作

    千次阅读 2019-11-06 09:32:12
    编写多线程程序时,对于不是原子操作的,需要引起程序员的额外注意。 一定要确保其对数据的操作是同步的,否则会引发数据安全问题。 i++不是原子操作 先来看一个例子,多线程下出现的数据不一致问题。 public ...
  • 通俗地讲,就是让多线程变成单线程。在C#中,可以将被锁定的资源理解成new出来的普通CLR对象。既然需要锁定的资源就是C#中的一个对象,我们就该仔细思考,到底什么样的对象能够成为一个锁对象(也叫同步对象)?在...
  • 编写多线程程序时,对于不是原子操作的,需要引起程序员的额外注意。 一定要确保其对数据的操作是同步的,否则会引发数据安全问题。 i++不是原子操作 先来看一个例子,多线程下出现的数据不一致问题。 public ...
  • 要提高具有多核的单个程序的性能,需要将该程序拆分为可以同时在个核上运行的线程 。 实际上,这向程序员提出了在代码中寻找并行性的问题。 我注意到许多硬件设计人员不了解MT挑战(因为他们从未编写过MT应用)。...
  • 实现客户聊天

    2018-10-20 15:33:07
    要使服务器可以接收个客户的连接,需要注意以下几个问题: 1.由于事先不知道客户端什么时候连过来,因此,服务器必须首先有一个线程负责个客户端连接。 结构如下: public class Server extends JFrame ...
  • 什么是可重入函数?

    2015-12-13 17:39:00
    可重入函数是指能够被线程“同时”调用的函数,并且能保证函数结果正确性的函数。...需要注意的是,不要调用不可重入的函数,当调用了不可重入的函数时,会使该函数也变成为不可重入的函数。一般驱
  • 为了提高具有多核的单个程序的性能,需要将该程序拆分为可以同时在个核上运行的线程 。 实际上,这向程序员提出了在代码中寻找并行性的问题。 我注意到许多硬件设计人员不了解MT挑战(因为他们从未编写过MT应用)...
  • 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)...1.2 4-2中finally中捕获异常需要注意什么? 答:无论try区块中是否发生异常,若有finally区块,则finally一定会被执行;如果程序编写的流程中先return了,...
  • 1. 本章学习总结 ...1.2 4-2中finally中捕获异常需要注意什么? 无论try区块中有无发生异常,若编写有finally区块,则finally区块一定会被执行。 如果程序编写的流程中先return了,而且也有final...
  • 操作系统(五)

    2020-02-03 16:40:34
    多线程程序具有不确定性和不可重现的特点 ->不经过专门设计,调试难度很高 不确定性要求并行程序的正确性 ->先思考清楚问题,把程序的行为设计清楚 ->切忌急于着手编写代码,碰到问题再调试 信号量和管程 ...
  • 156.使用 kafka 集群需要注意什么? 十六、Zookeeper 157.zookeeper 是什么? 158.zookeeper 都有哪些功能? 159.zookeeper 有几种部署模式? 160.zookeeper 怎么保证主从节点的状态同步? 161.集群中为什么要有主...
  • 可重入函数

    2017-07-16 20:44:39
    可重入函数 什么是可重入函数?...需要注意的是,不要调用不可重入函数,当调用了不可重入函数时,会使该函数也变为不可重入函数。一般驱动程序都是不可重入函数,因此在编写驱动程序时一定要注意重入问题。
  • 支持多线程分块下载,能更有效的发挥机器IO性能 支持300、301、302重定向下载链接下载 支持m3u8、hls协议的文件下载m3u8下载 支持m3u8边下边看的下载支持,点击查看详情 下载支持文件长度动态增加,文件下载初始化...

空空如也

空空如也

1 2 3 4 5
收藏数 93
精华内容 37
关键字:

编写多线程需要注意什么