Как получить объект из потока java
Перейти к содержимому

Как получить объект из потока java

  • автор:

Получить объект класс из потока в Java

Сервер приложения IBM WebSphere, соответственно, запущен на IBM JVM. Приложение работает в несколько потоков, как WebContainer, так и фоновые процессы. В отдельным потоке получаю все потоки, которые запущены в данной JVM, таким образом:

Set threadSet = Thread.getAllStackTraces().keySet(); for(Thread t: threadSet)

Можно ли каким-то образом получить список всех объектов, например класса java.sql.Connection, или его наследников, и уже от их имени выполнить какой-то запрос к БД. Например, несколько потоков имею свои подключения к БД и мне надо знать какой SQL_ID используется каждым потоком. Возможно это реализовать? Может есть другой способ решения данной задачи?

Как получить объект из потока java

Для создания нового потока мы можем создать новый класс, либо наследуя его от класса Thread, либо реализуя в классе интерфейс Runnable .

Наследование от класса Thread

Создадим свой класс на основе Thread:

class JThread extends Thread < JThread(String name)< super(name); >public void run() < System.out.printf("%s started. \n", Thread.currentThread().getName()); try< Thread.sleep(500); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >System.out.printf("%s fiished. \n", Thread.currentThread().getName()); > > public class Program < public static void main(String[] args) < System.out.println("Main thread started. "); new JThread("JThread").start(); System.out.println("Main thread finished. "); >>

Класс потока называется JThread. Предполагается, что в конструктор класса передается имя потока, которое затем передается в конструктор базового класса. В конструктор своего класса потока мы можем передать различные данные, но главное, чтобы в нем вызывался конструктор базового класса Thread, в который передается имя потока.

И также в JThread переопределяется метод run() , код которого собственно и будет представлять весь тот код, который выполняется в потоке.

В методе main для запуска потока JThread у него вызывается метод start() , после чего начинается выполнение того кода, который определен в методе run:

new JThread("JThread").start();
Main thread started. Main thread finished. JThread started. JThread finished.

Здесь в методе main в конструктор JThread передается произвольное название потока, и затем вызывается метод start() . По сути этот метод как раз и вызывает переопределенный метод run() класса JThread.

Обратите внимание, что главный поток завершает работу раньше, чем порожденный им дочерний поток JThread.

Аналогично созданию одного потока мы можем запускать сразу несколько потоков:

public static void main(String[] args)

Main thread started. Main thread finished. JThread 2 started. JThread 5 started. JThread 4 started. JThread 1 started. JThread 3 started. JThread 1 finished. JThread 2 finished. JThread 5 finished. JThread 4 finished. JThread 3 finished.

Ожидание завершения потока

При запуске потоков в примерах выше Main thread завершался до дочернего потока. Как правило, более распространенной ситуацией является случай, когда Main thread завершается самым последним. Для этого надо применить метод join() . В этом случае текущий поток будет ожидать завершения потока, для которого вызван метод join:

public static void main(String[] args) < System.out.println("Main thread started. "); JThread t= new JThread("JThread "); t.start(); try< t.join(); >catch(InterruptedException e) < System.out.printf("%s has been interrupted", t.getName()); >System.out.println("Main thread finished. "); >

Метод join() заставляет вызвавший поток (в данном случае Main thread) ожидать завершения вызываемого потока, для которого и применяется метод join (в данном случае JThread).

Main thread started. JThread started. JThread finished. Main thread finished.

Если в программе используется несколько дочерних потоков, и надо, чтобы Main thread завершался после дочерних, то для каждого дочернего потока надо вызвать метод join.

Реализация интерфейса Runnable

Другой способ определения потока представляет реализация интерфейса Runnable . Этот интерфейс имеет один метод run :

interface Runnable

В методе run() собственно определяется весь тот код, который выполняется при запуске потока.

После определения объекта Runnable он передается в один из конструкторов класса Thread:

Thread(Runnable runnable, String threadName)

Для реализации интерфейса определим следующий класс MyThread:

class MyThread implements Runnable < public void run()< System.out.printf("%s started. \n", Thread.currentThread().getName()); try< Thread.sleep(500); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >System.out.printf("%s finished. \n", Thread.currentThread().getName()); > > public class Program < public static void main(String[] args) < System.out.println("Main thread started. "); Thread myThread = new Thread(new MyThread(),"MyThread"); myThread.start(); System.out.println("Main thread finished. "); >>

Реализация интерфейса Runnable во многом аналогична переопределению класса Thread. Также в методе run определяется простейший код, который усыпляет поток на 500 миллисекунд.

В методе main вызывается конструктор Thread, в который передается объект MyThread. И чтобы запустить поток, вызывается метод start() . В итоге консоль выведет что-то наподобие следующего:

Main thread started. Main thread finished. MyThread started. MyThread finished.

Поскольку Runnable фактически представляет функциональный интерфейс, который определяет один метод, то объект этого интерфейса мы можем представить в виде лямбда-выражения:

public class Program < public static void main(String[] args) < System.out.println("Main thread started. "); Runnable r = ()-> < System.out.printf("%s started. \n", Thread.currentThread().getName()); try< Thread.sleep(500); >catch(InterruptedException e) < System.out.println("Thread has been interrupted"); >System.out.printf("%s finished. \n", Thread.currentThread().getName()); >; Thread myThread = new Thread(r,"MyThread"); myThread.start(); System.out.println("Main thread finished. "); > >

Как получить результат переменной из другого потока

Потоки создаются при подключении нового пользователя. В потоке выполняются различные функции, а также записываются логин и айпи откуда он зашел. Как мне можно узнать, например, переменную ip с другого потока?

94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:

Получить значение переменной из другого потока
Всем привет! Есть процедура, которая вызывает другую процедуру, но они работают в разных потоках.

Как вернуть результат работы функции, вызываемой из другого потока?
В фоновом потоке вызывается функция, возвращающая Boolean: Private Function Fn1() As Boolean .

Как получить данные из другого потока?
Здравствуйте. Приложение выполняется в 2 потока. В процессе выполнения необходимо получать данные.

Как получить доступ к элементу ListBox из другого потока
Прошу помощи. public partial class MainWindow : Window < .

Регистрация: 19.04.2015
Сообщений: 38
объектпотока.password не канает?)
Регистрация: 27.11.2012
Сообщений: 217
Можно по подробней?
2883 / 2295 / 769
Регистрация: 12.05.2014
Сообщений: 7,978
ты предлагаешь без единой строчки кода что-то советовать?
1046 / 662 / 216
Регистрация: 08.08.2014
Сообщений: 2,067

Garde
Чтобы запустить поток, вы создаёте объект некоего класса, который либо реализует интерфейс Runnable/Callable, либо наследуется от Thread. У этого класса, как и у любого другого, могут быть поля/методы к которым можно обращаться через ссылку на объект. Только в случае с многопоточной работой нужно не забывать про возможные проблемы с конкурентным доступом к ресурсам.

Простой пример (без синхронизации доступа к значению).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
import java.util.Random; public class MainApp { public static void main(String[] args) throws InterruptedException { SomeTask someTask = new SomeTask(); Thread someThread = new Thread(someTask); someThread.start(); System.out.println(""); while(someThread.isAlive()) { Thread.sleep(1000); System.out.format("%s ", someTask.getCurrentValue()); } System.out.println(""); } } class SomeTask implements Runnable { private int currentValue = -1; public int getCurrentValue() { return currentValue; } @Override public void run() { Random rnd = new Random(); try { while (true) { currentValue = rnd.nextInt(50); if (currentValue == 0) { break; } else { Thread.sleep(500); } } } catch (InterruptedException e) { } } }

Многопоточность в Java. Работа с потоками

Многопоточность в Java — это одновременное выполнение двух или более потоков для максимального использования центрального процессора (CPU — central processing unit). Каждый поток работает параллельно и не требует отдельной области памяти. К тому же, переключение контекста между потоками занимает меньше времени.

  • Лучшее использование одного центрального процессора: если поток ожидает ответ на запрос, отправленный по сети, другой поток в это время может использовать CPU для выполнения других задач. Кроме того, если у компьютера несколько CPU или у CPU несколько исполнительных ядер, многопоточность позволяет приложению использовать эти дополнительные ядра.
  • Оптимальное использование нескольких центральных процессоров или их ядер: необходимо использовать несколько потоков в приложении, чтобы задействовать все CPU или ядра CPU. Один поток может использовать максимум один CPU, иногда даже не полностью.
  • Улучшенный user experience в плане скорости ответа на запрос: например, если нажать на кнопку в графическом интерфейсе, то это действие отправит запрос по сети: здесь важно, какой поток выполняет этот запрос. Если используется тот же поток, который обновляет/уведомляет графический интерфейс, тогда пользователь может столкнуться с зависанием интерфейса, ожидающего ответа на запрос. Но этот запрос может выполнить фоновый поток, чтобы поток в графическом интерфейсе мог в это время реагировать на другие запросы пользователя.
  • Улучшенный user experience в плане справедливости распределения ресурсов: многопоточность позволяет справедливо распределять ресурсы компьютера между пользователями. Представьте сервер, который принимает запросы от клиентов и у него есть только один поток для выполнения этих запросов. Если клиент отправляет запрос, для обработки которого нужно много времени, все остальные запросы вынуждены ждать до тех пор, пока он завершится. Когда каждый клиентский запрос выполняется собственным потоком, ни одна задача не сможет полностью захватить CPU.

Процессы в Java: определение и функции

  • Процесс состоит из кода и данных. Он создается операционной системой при запуске приложения, является достаточно ресурсоемким и обладает собственным виртуальным адресным пространством.
  • Процессы работают независимо друг от друга. Они не имеют прямого доступа к общим данным в других процессах.
  • Операционная система выделяет ресурсы для процесса — память и время на выполнение.
  • Если один из процессов заблокирован, то ни один другой процесс не может выполняться, пока он не будет разблокирован.
  • Для создания нового процесса обычно дублируется родительский процесс.
  • Процесс может контролировать дочерние процессы, но не процессы того же уровня.

Что такое потоки

Поток — наименьшее составляющее процесса. Потоки могут выполняться параллельно друг с другом. Их также часто называют легковесными процессами. Они используют адресное пространство процесса и делят его с другими потоками.

Потоки могут контролироваться друг друга и общаться посредством методов wait(), notify(), notifyAll().

Состояния потоков

Потоки могут пребывать в нескольких состояниях:

  • New когда создается экземпляр класса Thread, поток находится в состоянии new. Он пока еще не работает.
  • Running поток запущен и процессор начинает его выполнение. Во время выполнения состояние потока также может измениться на Runnable, Dead или Blocked.
  • Suspended — запущенный поток приостанавливает свою работу, затем можно возобновить его выполнение. Поток начнет работать с того места, где его остановили.
  • Blocked — поток ожидает высвобождения ресурсов или завершение операции ввода-вывода. Находясь в этом состоянии поток не потребляет процессорное время.
  • Terminated — поток немедленно завершает свое выполнение. Его работу нельзя возобновить. Причинами завершения потока могут быть ситуации, когда код потока полностью выполнен или во время выполнения потока произошла ошибка (например, ошибка сегментации или необработанного исключения).
  • Dead — после того, как поток завершил свое выполнение, его состояние меняется на dead, то есть он завершает свой жизненный цикл.

Способы запуска потоков

Приложение, создающее экземпляр класса Thread, должно предоставить код, который будет работать в этом потоке. Существует два способа, чтобы добиться этого:

  • Предоставить реализацию объекта Runnable. Интерфейс Runnable определяет единственный метод — run, который должен содержать код, выполняющийся в потоке. Объект Runnable передается конструктору Thread. Например:
public class HelloRunnable implements Runnable < public void run() < System.out.println("Hello from a thread!"); >public static void main(String args[]) < (new Thread(new HelloRunnable())).start(); >>
  • Использовать подкласс Thread. Класс Thread сам реализует Runnable, хотя его метод run не делает ничего. Можно объявить класс Thread подклассом, предоставляя собственную реализацию метода run, как в примере:
public class HelloThread extends Thread < public void run() < System.out.println("Hello from a thread!"); >public static void main(String args[]) < (new HelloThread()).start(); >>

Обратите внимание, что оба примера вызывают Thread.start, чтобы запустить новый поток.

Какой из способов выбрать? Первый — с использованием объекта Runnable — более общий, потому что этот объект может превратить отличный от Thread класс в подкласс. Этот способ более гибкий и может использоваться для высокоуровневых API управления потоками.

Второй способ больше подходит для простых приложений, но есть условие: класс задачи должен быть потомком Thread.

Завершение процесса и потоки-демоны

В Java процесс завершается тогда, когда завершаются все его основные и дочерние потоки.

Потоки-демоны — это низкоприоритетные потоки, работающие в фоновом режиме для выполнения таких задач, как сбор «мусора»: они освобождают память неиспользованных объектов и очищают кэш. Большинство потоков JVM (Java Virtual Machine) являются потоками-демонами.

Свойства потоков-демонов:

  • Не влияют на закрытие JVM, когда все пользовательские потоки завершили свое исполнение;
  • JVM сама закрывается, когда все пользовательские потоки перестают выполняться;
  • Если JVM обнаружит работающий поток-демон, она завершит его, после чего закроется. JVM не учитывает, работает поток или нет.

Чтобы установить, является ли поток демоном, используется метод boolean isDaemon(). Если да, то он возвращает значение true, если нет, то — то значение false.

Завершение потоков

Завершение потока Java требует подготовки кода реализации потока. Класс Java Thread содержит метод stop(), но он помечен как deprecated. Оригинальный метод stop() не дает никаких гарантий относительно состояния, в котором поток остановили. То есть, все объекты Java, к которым у потока был доступ во время выполнения, останутся в неизвестном состоянии. Если другие потоки в приложении имели доступ к тем же объектам, то они могут неожиданно «сломаться».

Вместо вызова метода stop() нужно реализовать код потока, чтобы его остановить. Приведем пример класса с реализацией Runnable, который содержит дополнительный метод doStop(), посылающий Runnable сигнал остановиться. Runnable проверит его и остановит, когда будет готов.

public class MyRunnable implements Runnable < private boolean doStop = false; public synchronized void doStop() < this.doStop = true; >private synchronized boolean keepRunning() < return this.doStop == false; >@Override public void run() < while(keepRunning()) < // keep doing what this thread should do. System.out.println("Running"); try < Thread.sleep(3L * 1000L); >catch (InterruptedException e) < e.printStackTrace(); >> > >

Обратите внимание на методы doStop() и keepRunning(). Вызов doStop() происходит не из потока, выполняющего метод run() в MyRunnable.

Метод keepRunning() вызывается внутренней потоком, выполняющим метод run() MyRunnable. Поскольку метод doStop() не вызван, метод keepRunning() возвратит значение true, то есть поток, выполняющий метод run(), продолжит работать.

public class MyRunnableMain < public static void main(String[] args) < MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable); thread.start(); try < Thread.sleep(10L * 1000L); >catch (InterruptedException e) < e.printStackTrace(); >myRunnable.doStop(); > >

В примере сначала создается MyRunnable, а затем передается потоку и запускает его. Поток, выполняющий метод main() (главный поток), засыпает на 10 секунд и потом вызывает метод doStop() экземпляра класса MyRunnable. Впоследствии поток, выполняющий метод MyRunnable, остановится, потому что после того, как вызван doStop(), keepRunning() возвратит false.

Обратите внимание, если для реализация Runnable нужен не только метод run() (а например, еще метод stop() или pause()), реализацию Runnable больше нельзя будет создать с помощью лямбда-выражений. Понадобится кастомный класс или интерфейс, расширяющий Runnable, который содержит дополнительные методы и реализуется анонимным классом.

Метод Thread.sleep()

Поток может остановиться сам, вызвав статический метод Thread.sleep(). Thread.sleep() принимает в качестве параметра количество миллисекунд. Метод sleep() попытается заснуть на это количество времени перед возобновлениям выполнения. Thread sleep() не гарантирует абсолютной точности.

Приведем пример остановки потока Java на 10 секунд (10 тысяч миллисекунд) с помощью вызова метода Thread sleep():

try < Thread.sleep(10L * 1000L); >catch (InterruptedException e)

Поток, выполняющий код, уснет примерно на 10 секунд.

Метод join()

Метод join() экземпляра класса Thread используется для объединения начала выполнения одного потока с завершением выполнения другого потока. Это необходимо, чтобы один поток не начал выполняться до того, как завершится другой поток. Если метод join() вызывается на Thread, то выполняющийся в этот момент поток блокируется до момента, пока Thread не закончит выполнение.

Метод join() ждет не более указанного количества миллисекунд, пока поток умрет. Тайм-аут 0 (ноль) означает «ждать вечно».

Синтаксис:

public void join()throws InterruptedException

Например:

class TestJoinMethod1 extends Thread< public void run()< for(int i=1;i<=5;i++)< try< Thread.sleep(500); >catch(Exception e) System.out.println(i); > > public static void main(String args[])< TestJoinMethod1 t1=new TestJoinMethod1(); TestJoinMethod1 t2=new TestJoinMethod1(); TestJoinMethod1 t3=new TestJoinMethod1(); t1.start(); try< t1.join(); >catch(Exception e) t2.start(); t3.start(); > >

Результат:

1 2 3 4 5 1 1 2 2 3 3 4 4 5 5

Из примера видно, что как только поток t1 завершает выполнение задачи, потоки t2 и t3 начинают выполнять свои задачи.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *