Форум программистов, компьютерный форум CyberForum.ru

Модификатор synchronized и Runnable - Android

Восстановить пароль Регистрация
 
DarkVortex
102 / 68 / 18
Регистрация: 07.07.2014
Сообщений: 239
24.01.2016, 22:50     Модификатор synchronized и Runnable #1
Имеется сервис в котором крутится поток работающий с сетью, проблема в том, что при некоторых(больше месяца пытаюсь понять каких) обстоятельствах создается несколько экземпляров этого сервиса.
Перед запуском проверяю не запущен ли он так:
Java
1
2
3
4
5
6
7
8
9
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> rs = am.getRunningServices(Integer.MAX_VALUE);
boolean run = true;
for (int i = 0; i < rs.size(); i++) {
        ActivityManager.RunningServiceInfo rsi = rs.get(i);
    if(rsi.service.getClassName().contains("MyService")){
        run = false;   
        }
}
Но почему-то на некоторых устройствах сервис все равно запускается повторно(Зависимость в моделях и прошивках не нашел) но проблема возникает на android 4.4+.
Не придумав ничего лучше решил сделать так:
Java
1
2
3
4
5
6
public class MyClient implements Runnable{
    public synchronized void run(){
        //code
        
        }
}
Вручную запустил несколько потоков и как и ожидал все они выполнились последовательно. Выпустил в релиз но проблема не решилась. Некоторые клиенты работают с несколькими потоками, в нормальном случае в приложении не больше 6 потоков, у проблемных устройств их много больше. Физического доступа к ним к сожалению нет, на своих устройствах воспроизвести проблему не удалось.
Использование IntentService не подойдет, т.к. сервис должен стартовать в основном потоке.
Как можно гарантировать запуск только 1 экземпляра сервиса? Что-то у меня совсем не выходит(

Добавлено через 12 минут
Пример лога от проблемного устройства
Bash
1
2
3
4
5
6
7
8
9
10
1453658697.64 : 66 : 46.200.243.230 -> 1: LOGIN:||:356417062239070:||:API1:||:16596:||:26
1453658697.71 : 66 : 356417062239070 <- GET_CONNECTION_TYPE
1453658697.79 : 68 : 46.200.243.230 -> 1: LOGIN:||:356417062239070:||:API1:||:16550:||:26
Close duplicate connection 356417062239070
1453658697.85 : 68 : 356417062239070 <- GET_CONNECTION_TYPE
1453658697.85 : 69 : 46.200.243.230 -> 1: LOGIN:||:356417062239070:||:API1:||:16602:||:26
Close duplicate connection 356417062239070
1453658697.91 : 69 : 356417062239070 <- GET_CONNECTION_TYPE
1453658697.91 : 70 : 46.200.243.230 -> 1: LOGIN:||:356417062239070:||:API1:||:16623:||:26
Close duplicate connection 356417062239070
Предпоследнее значение id потока, последнее количество потоков в процессе, т.е. на модификатор synchronized ему явно плевать. Мне кажется это не очень нормальное поведение.

Добавлено через 56 минут
Теоретически дубликат сервиса может запуститься таким образом: поскольку за жизнью сервиса следит AlarmManager может произойти так, что android грохнет сервис из-за внешних факторов, сработает AlarmManager и запустит его, затем android решит воскресить старый сервис (он же липкий START_STICKY) и вот уже 2 сервиса. Возможно на загруженном кучей приложений устройстве это происходит достаточно часто.
Тогда задача сводится к следующему, как сделать так чтобы работал только 1 поток, попробую сделать из него singleton...
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
24.01.2016, 22:50     Модификатор synchronized и Runnable
Посмотрите здесь:

Java SE Не срабатывет пример с Runnable
Java SE synchronized
Оператор synchronized Java SE
Ant i runnable jar file Java SE
Android Как получить данные из Runnable процесса вызываемого из CallBack функции
Java SE Synchronized and monitor
Java SE Метод synchronized
Implements Runnable JavaFX
Android Потоки (Handler внутри synchronized)
PostDelayed можно ли в Runnable передавать аргумент, как-то так? Android
Блок synchronized Java
Не открывается Runnable JAR File Java

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
YuraAAA
 Аватар для YuraAAA
1563 / 1305 / 269
Регистрация: 25.10.2009
Сообщений: 3,424
Записей в блоге: 2
24.01.2016, 23:20     Модификатор synchronized и Runnable #2
Цитата Сообщение от DarkVortex Посмотреть сообщение
public synchronized void run
Этот synchronized вообще никак не влияет.
Цитата Сообщение от DarkVortex Посмотреть сообщение
несколько экземпляров этого сервиса.
Именно service? Тогда это невозможно
DarkVortex
102 / 68 / 18
Регистрация: 07.07.2014
Сообщений: 239
25.01.2016, 12:55  [ТС]     Модификатор synchronized и Runnable #3
Цитата Сообщение от YuraAAA Посмотреть сообщение
Этот synchronized вообще никак не влияет.
Так лучше?
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class SyncThread implements Runnable{
    private static final Object lock = new Object();        
    
    public void run() {
        synchronized(lock) {
            Log.d("TAG", "run() start");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Log.d("TAG", "run() end");
        }
    }
}
Java
1
2
3
4
5
6
        Thread sync_thread = new Thread(new SyncThread());
        sync_thread.start();
        Thread sync_thread2 = new Thread(new SyncThread());
        sync_thread2.start();
        Thread sync_thread3 = new Thread(new SyncThread());
        sync_thread3.start();
Лог:
Bash
1
2
3
4
5
6
D/TAG     (19792): run() start
D/TAG     (19792): run() end
D/TAG     (19792): run() start
D/TAG     (19792): run() end
D/TAG     (19792): run() start
D/TAG     (19792): run() end
Добавлено через 1 час 39 минут
Печаль вся в том, что класс этого потока у меня в отдельном dex лежит и довольно часто в фоне обновляется. Если dex файл перегрузить новый класс этого потока напрочь забудет о синхронизации и о том что его устаревшая копия уже работает он не узнает.

Добавлено через 1 час 36 минут
В итоге сделал вот так:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class SyncThread implements Runnable{
    public void run() {
        Set<Thread> all_stack = Thread.getAllStackTraces().keySet();
        for(Thread t : all_stack){
            if(t.getName().contains("SyncThread")){
                t.interrupt();
            }
        }
        Thread ct = Thread.currentThread();
        String tid = String.valueOf(ct.getId());
        ct.setName("SyncThread-" + tid); 
        
        Log.d("TAG", "run() start");
        while(!Thread.interrupted()){
            Log.d("TAG", "run() " + tid + " - " + String.valueOf(ct.getName()));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                ct.interrupt();
            }
        }
        Log.d("TAG", "run() end");
    }
}
Новый поток тормознет старый, даже если это уже 2 разных класса

Добавлено через 3 минуты
Конечно если их не запускать одновременно, но в моем случае это невозможно
YuraAAA
 Аватар для YuraAAA
1563 / 1305 / 269
Регистрация: 25.10.2009
Сообщений: 3,424
Записей в блоге: 2
25.01.2016, 12:55     Модификатор synchronized и Runnable #4
DarkVortex, да запустите Вы их через singleThreadPoolExecutor и всё
Yandex
Объявления
25.01.2016, 12:55     Модификатор synchronized и Runnable
Ответ Создать тему
Опции темы

Текущее время: 19:43. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru