Java передать потоку данные

Sharing a variable between multiple different threads

I’d like to share flag between main and help thread where these are two different Java classes I’ve created. Is any way to do this? Thanks!

7 Answers 7

Both T1 and T2 can refer to a class containing this variable.
You can then make this variable volatile, and this means that
Changes to that variable are immediately visible in both threads.

Volatile variables share the visibility features of synchronized but none of the atomicity features. This means that threads will automatically see the most up-to-date value for volatile variables. They can be used to provide thread safety, but only in a very restricted set of cases: those that do not impose constraints between multiple variables or between a variable’s current value and its future values.

And note the pros/cons of using volatile vs more complex means of sharing state.

Thank you for the answer but how would you refer to «flag» from inside T1, for instance? I’ve tried something like ParentClass.flag (where ParentClass is the class from whom I start «main» and «help») and it doesn’t seem to work.

Instantiate T1/T2 with a reference to their containing class, and make the flag a member of that class ?

In addition to the other suggestions — you can also wrap the flag in a control class and make a final instance of it in your parent class:

public class Test < class Control < public volatile boolean flag = false; >final Control control = new Control(); class T1 implements Runnable < @Override public void run() < while ( !control.flag ) < >> > class T2 implements Runnable < @Override public void run() < while ( !control.flag ) < >> > private void test() < T1 main = new T1(); T2 help = new T2(); new Thread(main).start(); new Thread(help).start(); >public static void main(String[] args) throws InterruptedException < try < Test test = new Test(); test.test(); >catch (Exception e) < e.printStackTrace(); >> > 

To make it visible between the instances of T1 and T2 you could make the two classes contain a reference to an object that contains the variable.

If the variable is to be modified when the threads are running, you need to consider synchronization. The best approach depends on your exact requirements, but the main options are as follows:

  • make the variable volatile ;
  • turn it into an AtomicBoolean ;
  • use full-blown synchronization around code that uses it.

Using static will not help your case.

Using synchronize locks a variable when it is in use by another thread.

You should use volatile keyword to keep the variable updated among all threads.

Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread safe. Thread safe means that a method or class instance can be used by multiple threads at the same time without any problem.

just to make the above statement clearer, volatile only promises visibility to other threads but not atomicity in the operation. Refer Volatile

  1. Making it static could fix this issue.
  2. Reference to the main thread in other thread and making that variable visible
Читайте также:  Html табличная верстка css

You can use lock variables «a» and «b» and synchronize them for locking the «critical section» in reverse order. Eg. Notify «a» then Lock «b» ,»PRINT», Notify «b» then Lock «a».

Please refer the below the code :

public class EvenOdd < static int a = 0; public static void main(String[] args) < EvenOdd eo = new EvenOdd(); A aobj = eo.new A(); B bobj = eo.new B(); aobj.a = Lock.lock1; aobj.b = Lock.lock2; bobj.a = Lock.lock2; bobj.b = Lock.lock1; Thread t1 = new Thread(aobj); Thread t2 = new Thread(bobj); t1.start(); t2.start(); >static class Lock < final static Object lock1 = new Object(); final static Object lock2 = new Object(); >class A implements Runnable < Object a; Object b; public void run() < while (EvenOdd.a < 10) < try < System.out.println(++EvenOdd.a + " A "); synchronized (a) < a.notify(); >synchronized (b) < b.wait(); >> catch (InterruptedException e) < e.printStackTrace(); >> > > class B implements Runnable < Object a; Object b; public void run() < while (EvenOdd.a < 10) < try < synchronized (b) < b.wait(); System.out.println(++EvenOdd.a + " B "); >synchronized (a) < a.notify(); >> catch (InterruptedException e) < e.printStackTrace(); >> > > > 
1 A 2 B 3 A 4 B 5 A 6 B 7 A 8 B 9 A 10 B 

AtomicBoolean

The succinct Answer by NPE sums up your three options. I’ll add some example code for the second item listed there: AtomicBoolean .

You can think of the AtomicBoolean class as providing some thread-safety wrapping around a boolean value.

If you instantiate the AtomicBoolean only once, then you need not worry about the visibility issue in the Java Memory Model that requires volatile as a solution (the first item in that other Answer). Also, you need not concern yourself with synchronization (the third item in that other Answer) because AtomicBoolean performs that function of protecting multi-threaded access to its internal boolean value.

Let’s look at some example code.

Firstly, in modern Java we generally do not address the Thread class directly. We now have the Executors framework to simplify handling of threads.

This code below is using Project Loom technology, coming to a future version of Java. Preliminary builds available now, built on early-access Java 16. This makes for simpler coding, with ExecutorService being AutoCloseable for convenient use with try-with-resources syntax. But Project Loom is not related to the point of this Answer; it just makes for simpler code that is easier to understand as “structured concurrency”.

The idea here is that we have three threads: the original thread, plus a ExecutorService that will create two more threads. The two new threads both report the value of our AtomicBoolean . The first new thread does so immediately, while the other waits 10 seconds before reporting. Meanwhile, our main thread sleeps for 5 seconds, wakes, changes the AtomicBoolean object’s contained value, and then waits for that second thread to wake and complete its work the report on the now-altered AtomicBoolean contained value. While we are installing seconds between each event, this is merely for dramatic demonstration. The real point is that these threads could coincidently try to access the AtomicBoolean simultaneously, but that object will protect access to its internal boolean value in a thread-safe manner. Protecting against simultaneous access is the job of the Atomic… classes.

try ( ExecutorService executorService = Executors.newVirtualThreadExecutor() ; ) < AtomicBoolean flag = new AtomicBoolean( true ); // This task, when run, will immediately report the flag. Runnable task1 = ( ) ->System.out.println( "First task reporting flag = " + flag.get() + ". " + Instant.now() ); // This task, when run, will wait several seconds, then report the flag. Meanwhile, code below waits a shorter time before *changing* the flag. Runnable task2 = ( ) -> < try < Thread.sleep( Duration.ofSeconds( 10 ) ); >catch ( InterruptedException e ) < e.printStackTrace(); >System.out.println( "Second task reporting flag = " + flag.get() + ". " + Instant.now() ); >; executorService.submit( task1 ); executorService.submit( task2 ); // Wait for first task to complete, so sleep here briefly. But wake before the sleeping second task awakens. try < Thread.sleep( Duration.ofSeconds( 5 ) ); >catch ( InterruptedException e ) < e.printStackTrace(); >System.out.println( "INFO - Original thread waking up, and setting flag to false. " + Instant.now() ); flag.set( false ); > // At this point, with Project Loom technology, the flow-of-control blocks until the submitted tasks are done. // Also, the `ExecutorService` is automatically closed/shutdown by this point, via try-with-resources syntax. System.out.println( "INFO - Tasks on background threads are done. The `AtomicBoolean` and threads are gone." + Instant.now() ); 

Methods such as AtomicBoolean#get and AtomicBoolean#set are built to be thread-safe, to internally protect access to the boolean value nested within. Read up on the various other methods as well.

First task reporting flag = true. 2021-01-05T06:42:17.367337Z INFO - Original thread waking up, and setting flag to false. 2021-01-05T06:42:22.367456Z Second task reporting flag = false. 2021-01-05T06:42:27.369782Z INFO - Tasks on background threads are done. The `AtomicBoolean` and threads are gone.2021-01-05T06:42:27.372597Z 

Pro Tip: When engaging in threaded code in Java, always study the excellent book, Java Concurrency in Practice by Brian Goetz et al.

Читайте также:  Python list получить индекс элемента

Источник

Java передать потоку данные

Класс Exchanger предназначен для обмена данными между потоками. Он является типизированным и типизируется типом данных, которыми потоки должны обмениваться.

Обмен данными производится с помощью единственного метода этого класса exchange() :

V exchange(V x) throws InterruptedException V exchange(V x, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException

Параметр x представляет буфер данных для обмена. Вторая форма метода также определяет параметр timeout — время ожидания и unit — тип временных единиц, применяемых для параметра timeout.

Данный класс очень просто использовать:

import java.util.concurrent.Exchanger; public class Program < public static void main(String[] args) < Exchangerex = new Exchanger(); new Thread(new PutThread(ex)).start(); new Thread(new GetThread(ex)).start(); > > class PutThread implements Runnable < Exchangerexchanger; String message; PutThread(Exchanger ex) < this.exchanger=ex; message = "Hello Java!"; >public void run() < try< message=exchanger.exchange(message); System.out.println("PutThread has received: " + message); >catch(InterruptedException ex) < System.out.println(ex.getMessage()); >> > class GetThread implements Runnable < Exchangerexchanger; String message; GetThread(Exchanger ex) < this.exchanger=ex; message = "Hello World!"; >public void run() < try< message=exchanger.exchange(message); System.out.println("GetThread has received: " + message); >catch(InterruptedException ex) < System.out.println(ex.getMessage()); >> >

В классе PutThread отправляет в буфер сообщение «Hello Java!»:

message=exchanger.exchange(message);

Причем в ответ метод exchange возвращает данные, которые отправил в буфер другой поток. То есть происходит обмен данными. Хотя нам необязательно получать данные, мы можем просто их отправить:

Логика класса GetThread аналогична — также отправляется сообщение.

В итоге консоль выведет следующий результат:

PutThread has received: Hello World! GetThread has received: Hello Java!

Источник

java передача информации между Thread

Есть JTextField , который хочу заполнить данными извне. Но если сервер не доступен, не хочу, чтоб зависло все приложение. Поэтому попытался заполнять его из другого потока, но явно что-то в этом не разбираюсь. И ничего не работает) Подскажите, куда глядеть. сейчас реализовано так:

final JTextField weightB = new JTextField(); getBruttoFBd(barcode, weightB); weightB.setBounds(weightF.getX() + weightF.getWidth() + 10, weightF.getY(), 50, 20); weightB.setEditable(false); 
public void getBruttoFBd(final String barcode, final JTextField weightB) < Thread mainThread = Thread.currentThread(); Thread t = new Thread(new Runnable() < public void run() < String t = "0"; t = SkSocket.patterString("getweight:"+barcode); if(t.equals("0")) < weightB.setText("База недоступна"); >else < weightB.setText(t); >> >); t.interrupt(); // В моем понимании должно уничтожить поток, если все ок) но это не точно > 

1 ответ 1

Thread.interrupt()

Thread.interrupt() нужен, чтоб послать потоку прерывание, которое обычно используется, чтоб попросить поток завершить работу. В вашем случае, это не нужно, так какой вызов, скорее всего (это зависит от устройства метода patterString ) попросту прервет вызов и поток завершит работу не получив никакого значения и не обновив поле weightB .

Читайте также:  Обход блокировок при парсинге python

Поток завершится, когда исполнение функции run дойдет до конца. Ситуация, когда вам может понадобиться interrupt() , это если вызов patterString заблокируется надолго. В этом случае поток t просто будет заблокирован. На приложение это будет влиять только таким образом, что если вызывать этот код много много раз, то закончится память у приложения.

Поэтому по-хорошему, делают грубо говоря отдельную кнопку, по нажатию на которую потоку t посылается interrupt() . Но это нужно делать не в getButtonFBd , а именно по отдельному событию, например, кнопку которую пользователь может нажать или по таймеру. Опять же, это будет работать, только если patterString обрабатывает interrupt() правильно (т.е. прерывает свою работу и бросает исключение InterruptedException).

Вызовы GUI кода из не-GUI потока

Вторая проблема, это попытка взаимодействовать с GUI компонентами из потока t . Это делать нельзя. Изменять компоненты можно только из потока, в котором запущен цикл обработки событий.

Обработчик, скажем, нажатия на кнопку уже запущен в GUI потоке и там можно это делать напрямую — вызывая методы у GUI объектов. В вашем же случае, когда запущен отдельный поток, можно воспользоваться методами из класса SwingUtilities:

 Thread t = new Thread(new Runnable() < public void run()< String t = "0"; t = SkSocket.patterString("getweight:"+barcode); if(t.equals("0")) < t = "База недоступна"; >SwingUtilities.invokeAndWait(() -> weightB.setText(t)); > >); 

В SwingUtilities.invokeAndWait передается функция, которая будет вызвана в GUI потоке, как только он освободится, если в данный момент он занят.

Источник

Оцените статью