synchronized before field outside of new Thread() - java

I want to make a part of asynchronous. I added a new Thread() and put to it code. What have to be done with fields and methods outside?
public class Record {
private String actionDetails;
public void setActionDetails(String actionDetails) {
this.actionDetails = actionDetails;
}
}
public class Recorder {
private Record record;
public void record(Record record){
this.record = record;
}
}
public class Test {
private static Recorder recorder = new Recorder();
private static StringBuilder builder;
public static void main(String[] args) {
builder.append("Test");
new Thread(() -> {
final Record record = new Record();
record.setActionDetails(builder.toString());
recorder.record(record);
}).start();
}
}
I think that for recorder, record(), setActionDetails() should use synchronized modificator and use StringBuffer instead StringBuilder.

Related

How can we ensure that instances of this class can be safely used by multiple threads?

This class is intended to allow users to write a series of messages, so that each message is identified with a timestamp and the name of the thread that wrote the message
public class Logger {
private StringBuilder contents = new StringBuilder();
public void log(String message) {
contents.append(System.currentTimeMillis());
contents.append(": ");
contents.append(Thread.currentThread().getName());
contents.append(message);
contents.append("\n");
}
public String getContents() {
return contents.toString();
}
}
If you really intend to collect logs like this, the most simple approach would be to use a synchronized section to make sure that only one thread at a time can access the contents field:
public class Logger {
private final StringBuilder contents = new StringBuilder();
public void log(String message) {
synchronized (contents) {
contents.append(System.currentTimeMillis());
contents.append('[');
contents.append(Thread.currentThread().getName());
contents.append("]: ");
contents.append(message);
contents.append("\n");
}
}
public String getContents() {
synchronized (contents) {
return contents.toString();
}
}
}
The field should be final in order to safely serve as a lock.
More about synchronized: https://www.baeldung.com/java-synchronized#the-synchronized-keyword
You can constrain exclusive access to a Logger object by simply adding the synchronized keyword to each method.
public class Logger {
private StringBuilder contents = new StringBuilder();
public synchronized void log(String message) {
contents.append(System.currentTimeMillis());
contents.append('[');
contents.append(Thread.currentThread().getName());
contents.append("]: ");
contents.append(message);
contents.append("\n");
}
public synchronized String getContents() {
return contents.toString();
}
}
This is equivalent to
public class Logger {
private final StringBuilder contents = new StringBuilder();
public void log(String message) {
synchronized (this) {
contents.append(System.currentTimeMillis());
contents.append('[');
contents.append(Thread.currentThread().getName());
contents.append("]: ");
contents.append(message);
contents.append("\n");
}
}
public String getContents() {
synchronized (this) {
return contents.toString();
}
}
}

Java FixedThreadPool with resources per thread?

This is a pseudocode version of my current working code:
public class DataTransformer {
private final boolean async = true;
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
public void modifyAsync(Data data) {
if (async) {
executorService.submit(new Runnable() {
#Override
public void run() {
modify(data);
}
});
} else {
modify(data);
}
}
// This should actually be a variable inside modify(byte[] data)
// But I reuse it to avoid reallocation
// This is no problem in this case
// Because whether or not async is true, only one thread is used
private final byte[] temp = new byte[1024];
private void modify(Data data) {
// Do work using temp
data.setReady(true); // Sets a volatile flag
}
}
Please read the comments. But now I want to use Executors.newFixedThreadPool(10) instead of Executors.newSingleThreadExecutor(). This is easily possible in my case by moving the field temp inside modify(Data data), such that each execution has it's own temp array. But that's not what I want to do because i want to reuse the array if possible. Instead I want for each of the 10 threads a temp array. What's the best way to achieve this?
As static variable is shared between all Threads, so you could declare as static. But if you want to use different values then either use Threadlocal or use different object.
With ThreadLocal you could do :
ThreadLocal<byte[]> value = ThreadLocal.withInitial(() -> new byte[1024]);
You could also use object like this:
public class Test {
public static void main(String[] args) {
try {
Test test = new Test();
test.test();
} catch (Exception e) {
e.printStackTrace();
}
}
class Control {
public volatile byte[] temp = "Hello World".getBytes();
}
final Control control = new Control();
class T1 implements Runnable {
#Override
public void run() {
String a = Arrays.toString(control.temp);
System.out.println(a);
}
}
class T2 implements Runnable {
#Override
public void run() {
String a = Arrays.toString(control.temp);
System.out.println(a);
}
}
private void test() {
T1 t1 = new T1();
T2 t2 = new T2();
new Thread(t1).start();
new Thread(t2).start();
}
}

make code async with forJoinPool

Hello I have with try catch structure and want to make code async in finally statement. I try to put this part into lambda and cast to task, to put it ForkJoinPool, but there is the Class Cast Exception. How to make async this part of code better. Does I have to use atomic or volatile before fields?
public class Record {
private String actionDetails;
public void setActionDetails(String actionDetails) {
this.actionDetails = actionDetails;
}
}
public class Recorder {
private Record record;
public void record(Record record){
this.record = record;
}
}
public class Test {
private static Recorder recorder = new Recorder();
private static StringBuilder builder;
public static void main(String[] args) {
try {
// other code
builder.append("Test");
} finally {
Runnable runnable = () -> {
final Record record = new Record();
record.setActionDetails(builder.toString());
recorder.record(record);
};
ForkJoinTask<?> task = (ForkJoinTask<?>)runnable;
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(task);
}
}
}
I mean this way:
ForkJoinPool pool = new ForkJoinPool();
pool.submit(() -> {
final Record record = new Record();
record.setActionDetails(builder.toString());
recorder.record(record);
});
but Is it need to use some modifier before fields ?

Signaling with shared objects

I am not able to understand, where to place methods
hasDataToProcess() & setHasDataToProcess() of MySignal class,
in App9 class to maintain synchronization on object of type NotThreadSafe.
Please help me the know the place !!!
//Signalling via shared objects
Code:
class MySignal{
protected boolean hasDataToProcess = false;
public synchronized boolean hasDataToProcess(){
return this.hasDataToProcess;
}
public synchronized void setHasDataToProcess(boolean hasData){
this.hasDataToProcess = true;
}
}
class NotThreadSafe{
StringBuilder builder = new StringBuilder();
public void add(String text){
this.builder.append(text);
}
public void display(){
System.out.println(builder);
}
}
public class App9 extends Thread {
NotThreadSafe instance;
protected MySignal sharedSignal = new MySignal();
public App9(NotThreadSafe sharedInstance){
this.instance = sharedInstance;
}
#Override
public void run(){
this.instance.add("sham");
this.instance.display();
}
public static void main(String[] args) {
NotThreadSafe sharedInstance = new NotThreadSafe();
for(int i=0; i<10 ; i++){
Thread t = new App9(sharedInstance);
t.start();
}
}
}

How to manage different TwitterStream from different Thread

i'm trying to execute different Thread using different TwitterStream object with an single authentication:
public class Support {
private static final String accessToken = "xxxxxxx";
private static final String accessTokenSecret = "xxxxxxx";
public static final AccessToken token = new AccessToken(accessToken, accessTokenSecret);
private static final String consumerKey = "xxxxxxx";
private static final String consumerSecret = "xxxxxxx";
private static final Configuration conf = new ConfigurationBuilder().setOAuthConsumerKey(consumerKey).setOAuthConsumerSecret(consumerSecret).build();
public static TwitterStreamFactory factory = new TwitterStreamFactory(conf);
}
In every Thread i do:
public MyThread1(){
this.twitterStream = Support.factory.getInstance(Support.token);
}
public void run(){
StatusListener listener = ... ;
twitterStream.addListener(listener);
FilterQuery fq = new FilterQuery();
fq.track(new String[]{"hashtag1","hashtag2"});
twitterStream.filter(fq);
}
public MyThread2(){
this.twitterStream = Support.factory.getInstance(Support.token);
}
public void run(){
StatusListener listener = ... ;
twitterStream.addListener(listener);
FilterQuery fq = new FilterQuery();
fq.track(new String[]{"hashtag3","hashtag4"});
twitterStream.filter(fq);
}
But it gives me authentication error.. multiple request of the same authentication. How can i solve?
Here is how I did it:
public class MyTwitterApp implements {
private Twitter twitter;
private Query query;
public MyTwitterApp (){
twitter = TwitterFactory.getSingleton();
}
public static void main(String[] args) {
MyTwitterApp twitterApp = new MyTwitterApp();
twitterApp.getStreamingTweets();
}
public void getStreamingTweets(){
StatusListener listener = new StatusListener(){
public void onStatus(Status status) {
handleStatus(status);
}
public void onDeletionNotice(StatusDeletionNotice statusDeletionNotice) {}
public void onTrackLimitationNotice(int numberOfLimitedStatuses) {}
public void onException(Exception ex) {ex.printStackTrace(); }
public void onScrubGeo(long arg0, long arg1) {}
public void onStallWarning(StallWarning arg0) {}
};
twitter.addListener(listener);
FilterQuery fq = new FilterQuery();
fq.count(0);
fq.track(new String[]{"#MyHashTag"});
twitter.filter(fq);
}
protected void handleStatus(Status tweet) {
if(tweet.isRetweet()){
return;
}
if(isMyHashTagTweet(tweet)){
//do something with tweet here
}
}
private boolean isMyHashTagTweet(Status tweet) {
HashtagEntity[] htes = tweet.getHashtagEntities();
for(HashtagEntity hte : htes){
if(hte.getText().equalsIgnoreCase("myhashtag")) {
return true;
}
}
return false;
}
}
Each thread will contain something like this.
twitter = TwitterFactory.getSingleton();
Will make sure you are reusing the same connection each time.
twitter.addListener(listener);
Will add a listener so that you will get called back to this thread (but you will get called back from every query added)
twitter.filter(fq);
Will add a new search query to follow.
isMyHashTagTweet(tweet)
Will check to make sure that the tweet returned by all queries live in your twitterStream are relevant for your current thread

Categories

Resources