I am trying to implement a busy waiting mechanism, using 2 flags. I get a deadlock, but just can't understand why... it looks to me as if it should work...
sorry for the long code, That's the shortest I succeeded to make it.
package pckg1;
public class MainClass {
public static void main(String[] args) {
Buffer b = new Buffer();
Producer prod = new Producer(b);
Consumer cons = new Consumer(b);
cons.start();
prod.start();
}
}
class Producer extends Thread {
private Buffer buffer;
public Producer(Buffer buffer1) {
buffer = buffer1;
}
public void run() {
for (int i = 0; i < 60; i++) {
while (!buffer.canUpdate)
;
buffer.updateX();
buffer.canUpdate = false;
buffer.canUse = true;
}
}
}
class Consumer extends Thread {
private Buffer buffer;
public Consumer(Buffer buffer1) {
buffer = buffer1;
}
public void run() {
for (int i = 0; i < 60; i++) {
while (!buffer.canUse)
;
buffer.consumeX();
buffer.canUse = false;
buffer.canUpdate = true;
}
}
}
class Buffer {
private int x;
public boolean canUpdate;
public boolean canUse;
public Buffer() {
x = 0;
canUpdate = true;
}
public void updateX() {
x++;
System.out.println("updated to " + x);
}
public void consumeX() {
System.out.println("used " + x);
}
}
I recommend that all the logic concerning Buffer should go into that class.
Also, accessing (and modifying) the flags must be protected, if 2 or more have access to it. That's why I put synchronised to the 2 methods.
class Buffer {
private int x;
private boolean canUpdate;
private boolean canUse;
public Buffer() {
x = 0;
canUpdate = true;
}
public synchronised void updateX() {
x++;
System.out.println("updated to " + x);
canUpdate = false;
canUse = true;
}
public synchronised void consumeX() {
System.out.println("used " + x);
canUpdate = true;
canUse = false;
}
public synchronised boolean canUse() {
return canUse;
}
public synchronised boolean canUpdate() {
return canUpdate;
}
}
Also, remove the canUpdate and canUse writes from the Producer and Consumer classes, and replace the reads (in the conditons) with the methods.
Also, it would be useful to introduce some Thread.sleep(100) in the waiting loops.
Related
I have Counter class with 3 methods out of which 2 are synchronized, I want increment() to execute first and then the count(), so that count for each thread should always be 3000.
Instead of calling the count() from run() I can call it from within increment() is the only approach I can think of, Is there any other way to do So?
class Counter {
int count=0;
void print() {
System.out.println("Print called by: "+Thread.currentThread().getName());
}
synchronized void increment()
{
for(int i=1;i<=3000;i++)
count++;
}
synchronized void getCount() {
System.out.println(count);
count =0;
}
}
class MyThread1 extends Thread {
Counter c;
MyThread1(Counter c) {
this.c = c;
}
public void run() {
c.print();
c.increment();
c.getCount();
}
}
class MyThread2 extends Thread {
Counter c;
MyThread2(Counter c) {
this.c = c;
}
public void run() {
c.print();
c.increment();
c.getCount();
}
}
public class Demo {
public static void main(String args[]) {
Counter obj = new Counter();
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}
Expected O/P in each case:
//The printing of "Print called by:" statement can be in any order as it's not synchronized but the count for each thread should always be 3000
Print called by: Thread-0
Print called by: Thread-1
3000
3000
Working example for my comment (You don't need MyThread1 and MyThread2):
public class Demo {
public static void main(String[] args) {
Counter obj = new Counter();
MyThread t1 = new MyThread(obj);
MyThread t2 = new MyThread(obj);
t1.start();
t2.start();
}
}
class Counter {
private final ThreadLocal<Integer> count = new ThreadLocal<Integer>() {
#Override
protected Integer initialValue() {
return 0;
}
};
void print() {
System.out.println("Print called by: " + Thread.currentThread().getName());
}
void increment() {
for (int i = 1; i <= 3000; i++)
count.set(count.get() + 1);
}
void getCount() {
System.out.println(count.get());
count.set(0);
}
}
class MyThread extends Thread {
Counter c;
MyThread(Counter c) {
this.c = c;
}
public void run() {
c.print();
c.increment();
c.getCount();
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo {
public static void main(String args[]) {
Counter obj = new Counter();
MyThread t1 = new MyThread(obj);
MyThread t2 = new MyThread(obj);
t1.start();
t2.start();
}
}
class Counter {
Lock lock = new ReentrantLock();
int count = 0;
void print() {
System.out.println("Print called by: " + Thread.currentThread().getName());
}
void increment() {
lock.lock();
for (int i = 1; i <= 3000; i++)
count++;
}
void getCount() {
System.out.println(count);
count = 0;
lock.unlock();
}
}
class MyThread extends Thread {
Counter c;
MyThread(Counter c) {
this.c = c;
}
public void run() {
c.print();
c.increment();
c.getCount();
}
}
You can use synchronized to block a thread.
here the example:
public void run() {
synchronized (Thread.class) {
c.print();
c.increment();
c.getCount();
}
}
synchronized needs an object as param, please use same object for both class MyThread1 and MyThread2
read https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html for more details.
Concurrent writing elements into the ConcurrentHashMap admits element. Requirements: writing must be done in different threads. Is there way to use advantages of the ConcurrentHashMap and do writing without blocking and sleeping?
Is there good code for iterator that accessed from different treads. Or is there other good variant to keep ieratian looking on the effectively-final requirement?
public class Task3v2 {
public static void main(String[] args) {
System.out.println("ConcurrentHashMap : "+timeIt(new ConcurrentHashMap<Integer, String>()));
}
static Iterator<Integer> integerIterator;
static {createIterator();}
private static void createIterator() {
integerIterator=
Stream.iterate(0, i -> i + 1).limit(100).collect(Collectors.toList()).iterator();
}
public static double timer(Runnable block) {
long start = System.nanoTime();
try {
block.run();
} finally {
long end = System.nanoTime();
return(end - start);
}
}
public static double timeIt(Map<Integer, String> map){
return timer(
()->{
new Thread(()->{
fillMap(map);
System.out.println("invoked");
readMap(map);
}).start();
});
}
private static void fillMap(Map<Integer, String> map){
int[] index = new int[1];
String[] tmp = new String[1];
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 0; i< 100; i++){
index[0] = i;
tmp[0] = "Name"+i;
new Thread(()->{
int a = integerIterator.next();
System.out.println("a :"+a);
map.put(a,"Name"+a);
}
).start();
}
}
private static void readMap(Map<Integer, String> map){
int[] index2 = new int[1];
for(int i = 0; i< 100; i++){
index2[0]=i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
System.out.println("map.get(index2[0]) :"+map.get(index2[0]));
}).start();
}
}
}
Finally the map must pass following tests:
public class Task3Test {
static ConcurrentHashMap<Integer, String> map;
#BeforeClass
public static void fillMap(){
map = new ConcurrentHashMap<>();
timeIt(map);
}
#Test
public void elementPresenceTest(){
//GIVEN
//map;
//WHEN
List<Integer> actualPresenceList = Stream.iterate(0, i -> i + 1).limit(100)
.filter(n->(map.entrySet().stream().map(Map.Entry::getKey)
.anyMatch(m->(n.equals(m))))).collect(Collectors.toList());
actualPresenceList.forEach(System.out::println);
System.out.println("size"+actualPresenceList.size());
//THEN
List<Integer>expectedPresenceList = Stream.iterate(0, i -> i + 1).limit(100).collect(Collectors.toList());
assertThat(actualPresenceList, Matchers.contains(expectedPresenceList));
}
#Test
public void elementAmountTest() {
assertThat(map.entrySet(), Matchers.hasSize(100));
}
}
Iterator is not acceptable for concurrency. Solution is:
static Queue integerQueue = Stream.iterate(0, i -> i + 1).limit(100).collect(Collectors.toCollection(LinkedBlockingQueue::new));
There is needed to keep sleeping for the readMap() method to provide time for the writing method. If there is needed to keep any data structure on adding new elements in concurrency environment, it should be used queue instead of map.
I am trying to print even and odd number using two different thread but It is throwing IllegalMonitorStateException .Kindly suggest me what am I doing wrong .
package com.rishi.threading;
public class MyThread {
public static class EvenThread extends Thread {
Boolean evenFlag;
Integer sharedCount;
public EvenThread(Boolean flag, Integer count) {
this.evenFlag = flag;
this.sharedCount = count;
}
public void run() {
printEven();
}
private void printEven() {
for (int i = 0; i < 10; i++) {
synchronized (evenFlag) {
if (!evenFlag) {
try {
evenFlag.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
evenFlag = false;
System.out.println("even thread :" + sharedCount++);
notifyAll();
}
}
}
}
public static class OddThread extends Thread {
Boolean evenflag;
Integer sharedCount;
public OddThread(Boolean flag, Integer count) {
this.evenflag = flag;
this.sharedCount = count;
}
public void run() {
printOdd();
}
private void printOdd() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
synchronized (evenflag) {
if (evenflag) {
try {
evenflag.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
evenflag = true;
System.out.println("odd thread :" + sharedCount++);
notifyAll();
}
}
}
}
public static void main(String[] args) {
Boolean evenFlag = new Boolean(true);
Integer sharedCount = new Integer(0);
EvenThread thread1 = new EvenThread(evenFlag, sharedCount);
thread1.setName("evenThread");
OddThread thread2 = new OddThread(evenFlag, sharedCount);
thread2.setName("oddthread");
thread1.start();
thread2.start();
}
}
I created two thread "EvenThread" and "OddThread".
Both the thread shares two common member variable ie evenFlag and sharedCount.
evenFlag -> just a flag which is set as true when sharedCount is even and set as false when shareDcount is set to odd number.
So both the thread is trying to get lock of evenFlag to control the printing of sharedCount.
I cant seem to find the problem on the code but it the server is not displaying anything. It displays the catch. Client seems find and it sets the players name and score and sends it but I cant seem to find the issue on this one why server is not displaying the name and score.
Here is my Client:
public class Client
{
private static final int BUFSIZE = 64;
public static void main(String[] args) throws IOException
{
try
{
int scores;
Scanner in = new Scanner(System.in);
Socket clntSock = new Socket("127.0.0.1", 6000);
System.out.println("What is the filename?");
String input = in.nextLine();
Scanner fileInput = new Scanner(new File(input));
ObjectOutputStream out = new
ObjectOutputStream(clntSock.getOutputStream());
Player playerObject = new Player();
playerObject.setName(fileInput.nextLine());
System.out.println(""+playerObject.getName());
for (int i = 0; i < 5; i++)
{
scores = Integer.parseInt(fileInput.nextLine());
playerObject.setScore(scores);
System.out.println(""+playerObject.getScores().get(i));
}
out.writeObject(playerObject);
in.close();
fileInput.close();
out.close();
clntSock.close();
}
catch ( UnknownHostException ex )
{
System.out.println( "Unknown host" );
}
}
}
and my Host:
public class Host
{
private static final int BUFSIZE = 64;
public static void main(String[] args) throws IOException
{
// Step 1: Create a ServerSocket.
ServerSocket servSock = new ServerSocket(6000);
PrintStream fileOut = new PrintStream("Datafromclient.txt");
try
{
// Step 2: Wait for a connection..
Socket clntSock = servSock.accept();
// Step 3: Get input and output streams.
System.out.println("Step 3: Get object input stream.,");
ObjectInputStream objectIn = new
ObjectInputStream(clntSock.getInputStream());
Player playerObjct = (Player)objectIn.readObject();
System.out.println("The name of Player: "+playerObjct.getName());
for(int i=0; i <5; i++)
{
System.out.println("Scores:"+playerObjct.getScores().get(i));
}
objectIn.close();
clntSock.close();
// Step 5: Close connection
objectIn.close();
clntSock.close();
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
System.err.println(e);
}
}
}
My player class:
public class Player
private String name;
private int playerId;
private int bestScore;
private static int numberOfPlayers = 0;
private ArrayList<Integer> scores = new ArrayList<Integer>();
/* -------------- CONSTRUCTOR --------------------------------------
*/
public Player()
{
numberOfPlayers++;
playerId = numberOfPlayers;
}
public Player(String name)
{
this.name = name;
}
//Create set method for setName
public void setName(String name)
{
this.name = name;
}
//Create set method for setScores
public void setScore(int score)
{
scores.add(score);
}
//Create get method for getPlayerId
public int getPlayerId()
{
return this.playerId;
}
//Create get method for getName
public String getName()
{
return this.name;
}
//Create get method for getScores
public ArrayList<Integer> getScores()
{
return scores;
}
//Create get method for getBestScore
public int getBestScore()
{
calculateBestScore();
return bestScore;
}
//Method to expose the value of numberOfPlayers
public static int getNumberOfPlayers()
{
return numberOfPlayers;
}
//Create get method for calcualteAverage
public double calculateAverage()
{
Integer sum = 0;
if(!scores.isEmpty())
{
for(Integer score : scores)
{
sum += score;
}
return sum.doubleValue() / scores.size();
}
return sum;
}
public void calculateBestScore()
{
bestScore = Collections.max(scores);
}
}
I was missing
import java.io.Serializable;
public class Player implements Serializable
now its working.
How can I cancel a thread from another class fetching/refreshing location. I am able to cancel a thread from within the same class. But I am unable to do this across classes. Declaring the GPSThread static did not help. Can anyone please guide?
Class1:
public class GPSListener {
/* Other instantiation code */
Dialog busyDialog1 = new Dialog("Refreshing Location...",
new String [] { "Cancel" },
new int [] { Dialog.CANCEL},
Dialog.CANCEL,
Bitmap.getPredefinedBitmap(Bitmap.HOURGLASS))
{
public void fieldChanged(Field field1, int context1)
{
GPSHandler.requestStop();
busyDialog1.cancel();
}
};
public String refreshCoordinates() {
String test = "nothing";
if (GPSHandler.isStopRequested())
{
GPSHandler.stopRequested = false;
return null;
}
GPSHandler.getInstance().setListener(this);
GPSHandler.getInstance().requestLocationUpdates();
if (GPSHandler.isStopRequested())
{
GPSHandler.stopRequested = false;
return null;
}
busyDialog1.setEscapeEnabled(false);
busyDialog1.show();
return test;
}
public void onLocationReceived(Coordinates location) {
lblLatitude.setText(Double.toString(location.getLatitude()));
lblLongitude.setText(Double.toString(location.getLongitude()));
busyDialog1.cancel();
}
}
Class 2:
public class GPSHandler {
private GPSThread _gpsThread;
private Coordinates _location;
private boolean _gotLocation;
private GPSListener _listener;
/** this class will be a Singleton, as the device only has one GPS system */
private static GPSHandler _instance;
/** #return the Singleton instance of the GPSHandler */
public static GPSHandler getInstance() {
if (_instance == null) {
_instance = new GPSHandler();
}
return _instance;
}
public static boolean stopRequested = false;
public synchronized static void requestStop() {
stopRequested = true;
}
public synchronized static boolean isStopRequested() {
return stopRequested;
}
/** not publicly accessible ... use getInstance() */
private GPSHandler() {
}
/** call this to trigger a new location fix */
public void requestLocationUpdates() {
if (_gpsThread == null || !_gpsThread.isAlive()) {
_gpsThread = new GPSThread();
_gpsThread.start();
}
}
public void setListener(GPSListener listener) {
// only supports one listener this way
_listener = listener;
}
private void setLocation(final Coordinates value) {
_location = value;
if (value.getLatitude() != 0.0 || value.getLongitude() != 0.0) {
_gotLocation = true;
if (_listener != null) {
// this assumes listeners are UI listeners, and want callbacks on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listener.onLocationReceived(value);
}
});
}
}
}
private class GPSThread extends Thread {
private void getLocationFromGoogle() {
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
writeDataGoogleMaps(outputStream2, cellID, lac);
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
final int code = dataInputStream2.readInt();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(code + "");
}
});
if (code == 0) {
final double latitude = dataInputStream2.readInt() / 1000000D;
final double longitude = dataInputStream2.readInt() / 1000000D;
setLocation(new Coordinates(latitude, longitude, 0.0f));
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(latitude+"-----"+longitude);
}
});
dataInputStream2.readInt();
dataInputStream2.readInt();
dataInputStream2.readUTF();
} else {
System.out.println("Error obtaining Cell Id ");
}
outputStream2.close();
inputStream2.close();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
private void tryGetLocationFromDevice() {
_gotLocation = false;
try {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
LocationProvider myLocationProvider = LocationProvider.getInstance(myCriteria);
try {
Location myLocation = myLocationProvider.getLocation(300);
setLocation(myLocation.getQualifiedCoordinates());
} catch ( InterruptedException iex ) {
System.out.println(iex.getMessage());
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
if (!_gotLocation) {
getLocationFromGoogle();
}
}
public void run() {
int bbMapsHandle = CodeModuleManager.getModuleHandle("net_rim_bb_lbs"); // OS 4.5 - 6.0
int bbMapsHandle60 = CodeModuleManager.getModuleHandle("net_rim_bb_maps"); // OS 6.0
if (bbMapsHandle > 0 || bbMapsHandle60 > 0) {
tryGetLocationFromDevice();
} else {
getLocationFromGoogle();
}
}
}
private void writeDataGoogleMaps(OutputStream out, int cellID, int lac) throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(out);
dataOutputStream.writeShort(21);
dataOutputStream.writeLong(0);
dataOutputStream.writeUTF("en");
dataOutputStream.writeUTF("Android");
dataOutputStream.writeUTF("1.0");
dataOutputStream.writeUTF("Web");
dataOutputStream.writeByte(27);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(3);
dataOutputStream.writeUTF("");
dataOutputStream.writeInt(cellID);
dataOutputStream.writeInt(lac);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.writeInt(0);
dataOutputStream.flush();
}
}
Your GPSThread object is currently declared as a private inner class within GPSHandler. If you want to stop execution (or indeed do anything with it) from outside the scope of GPSHandler you will need to mark it as public. You will also need to provide some public mechanism (e.g. a stop() method) to cancel the thread execution.
The most common way of doing this is to have a boolean flag inside your thread (e.g shouldStop) which is checked within your main execution loop inside run() to see if it should stop. When the stop() method is called shouldStop is set to true and your Thread will stop.
Here's a good example: How to stop threads in Java?
There's two groups of changes you should make.
Change the Stop Requested Flag
First, remember that encapsulation is a good thing in Object-Oriented languages. The isStopRequested() method, or stopRequested variable of the GPSHandler should not be used outside of that class. Your UI's GPSListener should not attempt to use either of those. I would change your GPSHandler to use this:
private static boolean stopRequested = false;
public synchronized static void requestStop() {
stopRequested = true;
}
private synchronized static boolean isStopRequested() {
return stopRequested;
}
Only requestStop() should be public. It looks like you made stopRequested public to allow the GPSListener to reset it. If it needs resetting, let the class that owns that variable do the resetting. For example, in GPSHandler:
/** call this to trigger a new location fix */
public void requestLocationUpdates() {
if (_gpsThread == null || !_gpsThread.isAlive()) {
// reset this stop flag:
stopRequested = false;
_gpsThread = new GPSThread();
_gpsThread.start();
}
}
requestLocationUpdates() is really the method that starts the thread, so it should be where stopRequested gets reset to false.
Also, another reason that you should not make stopRequested public and allow other classes to use it is that this is not generally thread-safe. One of the reasons to wrap stopRequested with the requestStop() and isStopRequested() methods is to add thread-safety. There's many ways to do that, but those two methods achieve thread-safety by being marked with the synchronized keyword.
Change How/Where You Check the Flag
After you make these fixes, you need to change where you check if a stop has been requested. You don't really want to check isStopRequested() in the refreshCoordinates() method. That method involves almost no work. Even though it starts the process of getting a location fix, that only starts a thread, but the actual work of getting the location is done on a background thread (your GPSThread). If requestStop() is called, it's very unlikely that it will be called in the middle of refreshCoordinates(), so that's not where you should check it.
Check isStopRequested() multiple times within the GPSHandler class's methods tryGetLocationFromDevice() and getLocationFromGoogle(). Those are the methods that perform slow processing. Those are the ones you might want to interrupt in the middle. So, something like this:
private void getLocationFromGoogle() {
try {
int cellID = GPRSInfo.getCellInfo().getCellId();
int lac = GPRSInfo.getCellInfo().getLAC();
String urlString2 = "http://www.google.com/glm/mmap";
if (isStopRequested()) return;
// Open a connection to Google Maps API
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection(urlString2);
HttpConnection httpConn2;
httpConn2 = (HttpConnection)connDesc.getConnection();
httpConn2.setRequestMethod("POST");
// Write some custom data to Google Maps API
OutputStream outputStream2 = httpConn2.openOutputStream();//getOutputStream();
writeDataGoogleMaps(outputStream2, cellID, lac);
if (isStopRequested()) return;
// Get the response
InputStream inputStream2 = httpConn2.openInputStream();//getInputStream();
DataInputStream dataInputStream2 = new DataInputStream(inputStream2);
// Interpret the response obtained
dataInputStream2.readShort();
dataInputStream2.readByte();
if (isStopRequested()) return;
final int code = dataInputStream2.readInt();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(code + "");
}
});
And in tryGetLocationFromDevice(), you could do this (make sure to add the member variable and new method below):
private LocationProvider _locationProvider; // must be a member variable!
public void requestStop() {
if (_locationProvider != null) {
// this will interrupt the _locationProvider.getLocation(300) call
_locationProvider.reset();
}
}
private void tryGetLocationFromDevice() {
_gotLocation = false;
try {
Criteria myCriteria = new Criteria();
myCriteria.setCostAllowed(false);
_locationProvider = LocationProvider.getInstance(myCriteria);
try {
Location myLocation = _locationProvider.getLocation(300);
setLocation(myLocation.getQualifiedCoordinates());
} catch ( InterruptedException iex ) {
// this may be caught if stop requested!!!!
System.out.println(iex.getMessage());
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
} catch ( LocationException lex ) {
System.out.println(lex.getMessage());
}
if (!_gotLocation && !isStopRequested()) {
getLocationFromGoogle();
}
}
Then, call the GPSThread.requestStop() method from the outer GPSHandler.requestStop() method:
public synchronized static void requestStop() {
stopRequested = true;
if (_gpsThread != null) {
_gpsThread.requestStop();
}
}