精华内容
下载资源
问答
  • 2020-12-22 20:04:01

    问题描述

    最近在做飞机大战游戏,发现一个问题,就是游戏运行了一定时间后会停止,同时eclipse会报出空指针异常。
    为此,我针对性地在 遍历list列表并取出列表元素 的for循环中输出每个对象,发现确实会出现null值,且null值出现是随机的,因此我意识到应该不是代码问题(因为如果是代码问题,每次bug的位置、时间等条件应保持一致)。
    但是由于我代码中有碰撞检测并移除子弹和敌机的操作,怀疑可能是由于移除导致list该位置元素为空,但还没来得及更新就被其他代码调用的情况,因此我为了确定问题根源,将移除的方法注释掉,发现仍然会出现空指针报错。

    原因分析:

    我后来通过百度搜索终于确定了问题根源:ArrayList
    简单来说,ArrayList不适合多线程高并发的情况,会出现内部某些位置为null的情况。核心原因是,ArrayList的add的方法不是线程安全的,是非原子性的,add操作可以简单理解为两个步骤:

    1.给索引位置赋值

    2.size加1

    如果现在有两个线程a,b,size为5,索引为4,a线程读到索引位值时,将值赋值到这个位置,这时cpu时间片让出,b线程读到的索引位置也是4,将size加1。这个时候a线程恢复cpu时间片,size加1。这样,索引位置值变成了a线程赋值的值,b线程的值被覆盖了,但是size却加了2次,这样取值的时候自然就取到了空值。

    解决办法:

    1.尽量避免在多线程的环境中使用ArrayList.

    2.使用Collections.synchronizedList 方法包装list,它里面使用的是synchronized关键字来实现线程安全的。
    List list = Collections.synchronizedList(newArrayList());

    3.vector

    4.CopyOnWriteArrayList(线程安全,基于copy思想,但是数据过多,可能导致gc频繁,需要衡量。)

    参考博客:

    《高并发下ArrayList空值(null)问题》,作者:归海一刀之渔舟唱晚

    更多相关内容
  • 线程什么情况下会造成死锁 什么是死锁? 死锁:假如你有两把a、b,当线程1拿到a的时候又想去拿b,线程2拿到了b又想去拿a,这时候两个线程竞争谁也拿不到,导致线程无法运行下去,造成了死锁。 代码...

    线程中什么情况下会造成死锁

    什么是死锁?
    死锁:假如你有两把锁a、b,当线程1拿到锁a的时候又想去拿锁b,线程2拿到了锁b又想去拿锁a,这时候两个线程竞争谁也拿不到锁,导致线程无法运行下去,造成了死锁。

    代码验证如下

    #include<stdio.h>
    #include<pthread.h>
    //int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
      //                        void *(*start_routine) (void *), void *arg)
    int data=0;
    
    pthread_mutex_t mutex;
    pthread_mutex_t mutex2;
    
    void *fun1(void *arg)
    {
    
            pthread_mutex_lock(&mutex);
            sleep(1);
            pthread_mutex_lock(&mutex2);
            while(1)
            {
                    data++;
                    printf("t1 data=%d\n",data);
                    if(data==3)
                    {
                            pthread_mutex_unlock(&mutex);
                            pthread_exit(NULL);
                    }
                    sleep(1);
            }
    }
    
    void *fun2(void *arg)
    {
    
            while(1)
            {
                    pthread_mutex_lock(&mutex2);
                    sleep(1);
                    pthread_mutex_lock(&mutex);
                    data++;
                    pthread_mutex_unlock(&mutex2);
                    sleep(1);
                    printf("t2 data=%d\n",data);
    
            }
    }
    int main()
    {
            pthread_t t1;
            pthread_t t2;
            int ret;
            int t=100;
    
            pthread_mutex_init(&mutex,NULL);
            pthread_mutex_init(&mutex2,NULL);
            ret=pthread_create(&t1,NULL,fun1,(void *)&t);
            if(ret==0)
            {
                    printf("main:create success\n");
            }
    
            ret=pthread_create(&t2,NULL,fun2,(void *)&t);
            if(ret==0)
            {
                    printf("main:create success\n");
            }
            printf("main:%ld\n",(unsigned long)pthread_self());
    
    
            pthread_join(t1,NULL);
            pthread_join(t2,NULL);
    
            pthread_mutex_destroy(&mutex);
            pthread_mutex_destroy(&mutex2);
            return 0;
    }
    
    展开全文
  • The thread T is then removed from the wait set for this object and re-enabled for thread 然后线程T就从等待集合中移除,和其他线程一起抢占资源,然后执行 scheduling. It then competes in the usual ...

     

     This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Thread T becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:
    1. Some other thread invokes the notify method for this object and thread T happens to be arbitrarily chosen as the thread to be awakened.

    其他线程调用了notify
    2. Some other thread invokes the notifyAll method for this object.

    其他线程调用了notifyall
    3. Some other thread interrupts thread T.

    其他线程中断了次线程
    4. The specified amount of real time has elapsed, more or less. If timeout is zero, however, then real time is not taken into consideration and the thread simply waits until notified.

    执行的实时时间到了,如果超时时间设置为0,那么将会忽略配置的超时时间,一直等到其他线程唤醒。

    The thread T is then removed from the wait set for this object and re-enabled for thread

    然后线程T就从等待集合中被移除,和其他线程一起抢占资源,然后执行

    scheduling. It then competes in the usual manner with other threads for the right to synchronize on the object; once it has gained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.

    关注我,不迷路。


     

    展开全文
  • 所谓死锁是指线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。 二、死锁产生的必要条件: **互斥条件:**线程要求对所分配的资源(如打印机)进行排他性控制,即在一段...

    一、死锁的定义:
    所谓死锁是指多个线程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进 。

    二、死锁产生的必要条件:
    **互斥条件:**线程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某 资源仅为一个线程所占有。此时若有其他线程请求该资源,则请求线程只能等待。

    **不剥夺条件:**线程所获得的资源在未使用完毕之前,不能被其他线程强行夺走,即只能由获得该资源的线程自己来释放(只能是主动释放)。

    **请求和保持条件:**线程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他线程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。

    **循环等待条件:**存在一种线程资源的循环等待链,链中每一个线程已获得的资源同时被链中下一个线程所请求。即存在一个处于等待状态的线程集合{Pl, P2, …, pn},其中Pi等待的资源被P(i+1)占有(i=0, 1, …, n-1),Pn等待的资源被P0占有,如图所示:
    在这里插入图片描述

    产生死锁的一个例子代码:

    1package itheima.com; 
    2/**
    3.* 一个简单的死锁类   
    4.* 当 DeadLock 类的对象 flag==1 时(td1),先锁定 o1,睡眠 500 毫秒   
    5.* 而 td1 在睡眠的时候另一个 flag==0 的对象(td2)线程启动,先锁定 o2,睡眠 500 毫秒
    6.* td1 睡眠结束后需要锁定 o2 才能继续执行,而此时 o2 已被 td2 锁定;   
    7.* td2 睡眠结束后需要锁定 o1 才能继续执行,而此时 o1 已被 td1 锁定;   
    8.* td1、td2 相互等待,都需要得到对方锁定的资源才能继续执行,从而死锁。   
    9.*/     
    10public class DeadLock implements Runnable {     
    11public int flag = 1;     
    12//静态对象是类的所有对象共享的     
    13private static Object o1 = new Object(), o2 = new Object();     
    14public void run() {     
    15.        System.out.println("flag=" + flag);     
    16if (flag == 1) {     
    17synchronized (o1) {     
    18try {     
    19.                    Thread.sleep(500);     
    20} catch (Exception e) {     
    21.                    e.printStackTrace();     
    22}     
    23synchronized (o2) {     
    24.                    System.out.println("1");     
    25}     
    26}     
    27}     
    28if (flag == 0) {     
    29synchronized (o2) {     
    30try {     
    31.                    Thread.sleep(500);     
    32} catch (Exception e) {     
    33.                    e.printStackTrace();     
    34}     
    35synchronized (o1) {     
    36.                    System.out.println("0");     
    37}     
    38}     
    39}     
    40}       
    41public static void main(String[] args) {        
    42.        DeadLock td1 = new DeadLock();     
    43.        DeadLock td2 = new DeadLock();     
    44.        td1.flag = 1;     
    45.        td2.flag = 0;     
    46//td1,td2 都处于可执行状态,但 JVM 线程调度先执行哪个线程是不确定的。     47.        //td2 的 run()可能在 td1 的 run()之前运行     
    48new Thread(td1).start();
    49new Thread(td2).start();     
    50}     
    51}        
    

    如何避免死锁 :

    在有些情况下死锁是可以避免的。两种用于避免死锁的技术:

    1)加锁顺序(线程按照一定的顺序加锁)

    1package itheima.com; 
    2public class DeadLock {     
    3public int flag = 1;     
    4//静态对象是类的所有对象共享的     
    5private static Object o1 = new Object(), o2 = new Object();     
    6public void money(int flag) { 
    7this.flag=flag; 
    8if( flag ==1){ 
    9synchronized (o1) {     
    10try {     
    11.                     Thread.sleep(500);     
    12} catch (Exception e) {     
    13.                     e.printStackTrace();     
    14}     
    15synchronized (o2) {     
    16.                     System.out.println("当前的线程是"+ 
    17.                       Thread.currentThread().getName()+" "+"flag 的值"+"1");     18}     
    19}         
    20}         
    21if(flag ==0){ 
    22synchronized (o2) {     
    23try {     
    24.                    Thread.sleep(500);     
    25} catch (Exception e) {     
    26.                    e.printStackTrace();     
    27}     
    28synchronized (o1) {     
    29.                    System.out.println("当前的线程是"+ 
    30.                      Thread.currentThread().getName()+" "+"flag 的值"+"0");     31}     
    32}       
    33} 
    34} 
    3536public static void main(String[] args) {                
    37final DeadLock td1 = new DeadLock();     
    38final DeadLock td2 = new DeadLock();         
    39.        td1.flag = 1;     
    40.        td2.flag = 0;     
    41//td1,td2 都处于可执行状态,但 JVM 线程调度先执行哪个线程是不确定的。     42.        //td2 的 run()可能在 td1 的 run()之前运行     
    43final Thread t1=new Thread(new Runnable(){ 
    44public void run() { 
    45.    td1.flag = 1;  
    46.    td1.money(1); 
    47}         
    48}); 
    49.        t1.start(); 
    50.        Thread t2= new Thread(new Runnable(){ 
    51public void run() { 
    52// TODO Auto-generated method stub 
    53try { 
    54//让 t2 等待 t1 执行完 
    55.     t1.join();//核心代码,让 t1 执行完后 t2 才会执行 
    56} catch (InterruptedException e) { 
    57// TODO Auto-generated catch block 
    58.     e.printStackTrace(); 
    59} 
    60.    td2.flag = 0; 
    61.    td1.money(0); 
    62}       
    63}); 
    64.        t2.start(); 
    65}     
    66}
    

    结果:

    当前的线程是 Thread-0 flag 的值 1
    当前的线程是 Thread-1 flag 的值 0

    2)加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

    1package itheima.com; 
    2import java.util.concurrent.TimeUnit; 
    3import java.util.concurrent.locks.Lock; 
    4import java.util.concurrent.locks.ReentrantLock; 
    5public class DeadLock { 
    6public int flag = 1;     
    7//静态对象是类的所有对象共享的     
    8private static Object o1 = new Object(), o2 = new Object();     
    9public void money(int flag) throws InterruptedException {    
    10this.flag=flag; 
    11if( flag ==1){ 
    12synchronized (o1) {                      
    13.                     Thread.sleep(500);                
    14synchronized (o2) {     
    15.                     System.out.println("当前的线程是"+ 
    16.                       Thread.currentThread().getName()+" "+"flag 的值"+"1");     17}     
    18}         
    19}         
    20if(flag ==0){ 
    21synchronized (o2) {    
    22.                    Thread.sleep(500);        
    23synchronized (o1) {     
    24.                    System.out.println("当前的线程是"+ 
    25.                      Thread.currentThread().getName()+" "+"flag 的值"+"0");     26}     
    27}       
    28} 
    29}     
    3031public static void main(String[] args) {     
    32final Lock lock = new ReentrantLock();   
    33final DeadLock td1 = new DeadLock();     
    34final DeadLock td2 = new DeadLock();         
    35.        td1.flag = 1;     
    36.        td2.flag = 0;     
    37//td1,td2 都处于可执行状态,但 JVM 线程调度先执行哪个线程是不确定的。     38.        //td2 的 run()可能在 td1 的 run()之前运行     
    3940final Thread t1=new Thread(new Runnable(){ 
    41public void run() { 
    42// TODO Auto-generated method stub 
    43.    String tName = Thread.currentThread().getName(); 
    4445.    td1.flag = 1;     
    46try {   
    47//获取不到锁,就等 5 秒,如果 5 秒后还是获取不到就返回 false   48.                    if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) {   
    49.                     System.out.println(tName + "获取到锁!");   
    50} else {   
    51.                     System.out.println(tName + "获取不到锁!");   
    52return;   
    53}   
    54} catch (Exception e) {   
    55.                    e.printStackTrace();   
    56}   
    5758try {                          
    59.                 td1.money(1);                      
    60} catch (Exception e) {   
    61.                 System.out.println(tName + "出错了!!!");   
    62} finally {   
    63.                    System.out.println("当前的线程是"+Thread.currentThread().getName()+"释放锁!! ");   
    64.                    lock.unlock();   
    65}   
    66}         
    67}); 
    68.        t1.start(); 
    69.        Thread t2= new Thread(new Runnable(){ 
    70public void run() { 
    71.    String tName = Thread.currentThread().getName(); 
    72// TODO Auto-generated method stub 
    73.    td1.flag = 1;     
    74try {   
    75//获取不到锁,就等 5 秒,如果 5 秒后还是获取不到就返回 false   76.                    if (lock.tryLock(5000, TimeUnit.MILLISECONDS)) {   
    77.                     System.out.println(tName + "获取到锁!");   
    78} else {   
    79.                     System.out.println(tName + "获取不到锁!");   
    80return;   
    81}   
    82} catch (Exception e) {   
    83.                    e.printStackTrace();   
    84}   
    85try {   
    86.                 td2.money(0);   
    87} catch (Exception e) {   
    88.                 System.out.println(tName + "出错了!!!"); 
    89} finally {   
    90.                    System.out.println("当前的线程是"+Thread.currentThread().getName()+"释放锁!!");   
    91.                    lock.unlock();   
    92}  
    93}    
    94}); 
    95.        t2.start();   
    96}     
    97}
    

    打印结果:

    Thread-0 获取到锁:
    当前的线程是 Thread-0 flag 的值 1
    当前的线程是 Thread-0 释放锁::
    Thread-1 获取到锁:
    当前的线程是 Thread-1 flag 的值 0
    当前的线程是 Thread-1 释放锁::

    展开全文
  • 什么情况下会线程安全问题

    千次阅读 2017-08-21 01:12:32
    Q:什么情况下会有线程安全问题 A:当某个实现多线程的线程类中有实例变量时 ps:有状态,无状态对象是什么概念 有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存...
  • 多线程死锁,活锁,竞争问题总结。举例分析产生各种的原因以及解决方法
  • 在实际应用中经常会遇到的与相关的异常情况,当两个事务需要一组有冲突的,而不能将事务继续下去的话,就会出现死锁,严 重影响应用的正常执行。 在数据库中有两种基本的类型:排它(Exclusive Locks,即X...
  • 多线程什么出现安全问题

    千次阅读 2020-09-08 23:07:19
    一、多线程什么出现安全问题</center> 为什么多线程在执行的时候会造成安全问题呢,下面我们来了解一下所谓的线程安全倒地时怎么来的。 ## 一、内存模型简述 > 了解的同学都知道java内存模型分为了...
  • 什么情况下使用多线程

    万次阅读 2017-04-03 17:42:17
    如果你的应用程序需要采取以下的操作,那么你尽可在编程的时候考虑多线程机制: 连续的操作,需要花费忍无可忍的过长时间才可能完成 并行计算 为了等待网络、文件系统、用户或其他I/O响应而耗费大量的执行时间 ...
  • 众所周知,多线程会造成线程安全问题,那么多线程什么会导致线程安全问题呢? 一:首先了解jvm内存的运行时数据区 1.堆区:存储对象实例(和实例变量),数组等 2.java虚拟机栈(方法·栈),存放方法声明,...
  • 最近在学习JUC框架的时候,发现了很工具类都是支持可中断的,如AQS、FutureTask都是可以在线程执行中,支持对于中断的响应,所以需要对线程中断有个了解,才能更好的学习JUC的源码。 线程中断的作用: 线程中断...
  • Java_多线程_释放问:Java多线程运行环境中,在哪些情况下会使对象释放?答:由于等待一个的线程只有在获得这把之后,才能恢复运行,所以让持有的线程在不再需要的时候及时释放是很重要的。在以下情况...
  • 一张图读懂Java多线程

    2021-01-20 03:44:59
     2)何种情况下获取到了,何种情况下会释放  2、还是那张图  3、详细图解  1)Thread t = new Thread(),初始化一个线程,实际上是一个普通对象,此时他的状态为New  2)t.start(); 线程处于绪...
  • HashMap在高并发下会形成环形链表 参考文章HashMap在高并发下会形成环形链表
  • 一旦系统中出现了阻塞现象,那么可以根据实际情况来使用多线程技术提高运行效率. 2.依赖 依赖.业务分为两个执行过程,分别是A和B.当A业务发生阻塞时,B业务的执行不依赖A业务的执行结果,这时可以使用多线程技术来提高...
  • 多线程最终解决的就是“等待”的问题,所以简单总结的使用场景: 1 通过并行计算提高程序执行性能 2 需要等待网络、I/O 响应导致耗费大量的执行时间,可以采用异步线程的方式来减少阻塞 ...
  • python多线程

    2020-12-22 21:38:10
    虽然python能运行多线程,但是因为GIL所以同一时刻只有一条线程在python解释器运行。多线程下python虚拟机按以下方式执行:1. 设置GIL2. 切换到一条线程去运行3. 运行:a. 执行python2虚拟机运行1000字节指令 或者 ...
  • 在以下情况下,持有线程会释放: 1. 执行完同步代码块。 2. 在执行同步代码块的过程中,遇到异常而导致线程终止。 3. 在执行同步代码块的过程中,执行了所属对象的wait()方法,这个线程会释放,进行...
  • 在单线程中不会出现线程安全问题,而在多线程编程中,有可能会出现同时访问同一个资源的情况,这种资源可以是各种类型的的资源:一个变量、一个对象、一个文件、一个数据库表等,而当多个线程同时访问同一个资源的...
  • 多线程的安全问题

    千次阅读 2022-02-24 16:52:47
    多线程的环境下数据什么时候会存在线程安全的问题? 1.多线程并发 2.线程之间有共享数据 3.线程之间的共享数据有修改行为 如何解决线程安全的问题? 让线程不能并发,也就是让线程排队执行,这种机制称为...
  • 线程什么时候会进入阻塞状态?

    千次阅读 2020-04-26 23:08:13
    阻塞的情况分三种:  1等待阻塞(o.wait->...运行的线程在获取对象的同步时,若该同步锁被别的线程占用,则 JVM 会把该线程放入池中。  3其他阻塞(sleep/join) 运行的线程执行 Thread.sleep(...
  • python如何切换线程

    2021-01-14 08:44:25
    线程首先获取一个条件变量,如果条件不足,则该线程等待(wait)并释放条件变量,如果满足就执行线程,也可以通知其他状态为 wait 的线程。其他处于 wait 状态的线程接到通知后会重新判断条件。下面为一个有趣的...
  • 多线程关于的运用

    2020-05-21 04:27:03
    线程同步是为了解决并发问题的,由于同一进程的线程共享同一块存储空间的情况下会带来一些访问的冲突问题,所以为了保证数据在方法中访问时的正确性,我们会提前加入机制最常用的一开始就是synchronized...
  • 多线程
  • 最近我正在处理C#中关于timeout行为的一些bug。解决方案非常有意思,所以我在这里分享给广大博友们。...我们无法预估这次操作会持续多久,但一般情况下会持续不到一秒。为了避免弹出窗口一闪而过,
  • mysql在什么情况下会发生死锁

    千次阅读 2020-09-27 20:46:01
    mysql InnoDB在什么情况下会发生死锁的现象什么是死锁会出现死锁的几种情况1、一张表两行记录交叉申请互斥2、两张表两行记录交叉申请互斥3、聚集索引与非聚集索引冲突4、聚集索引冲突5、间隙冲突 这片文章,...
  • java aqs中什么情况下会调用cancelAcquire方法

    千次阅读 热门讨论 2020-08-09 22:00:37
    //阻塞当前线程,等待唤醒, final boolean acquireQueued(final Node node, int arg) { boolean failed = true;//true代表成功获取 try { boolean interrupted = false; //线程在等待过程中是否中断 for (;;...
  • python多线程什么时候使用

    千次阅读 2019-03-18 12:31:49
    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段。并行是指两个或多个独立的操作同时进行。注意这里是同时进行,区别于并发,在一个时间段内执行多个操作。在单核时代,多个线程是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,117
精华内容 30,046
关键字:

多线程什么情况下会出现线程被锁