Consider the following code:
class Chicks {
synchronized void yack(long id) {
for(int x = 1; x < 3; x++) {
System.out.print(id + " ");
Thread.yield();
}
}
}
public class ChicksYack implements Runnable {
Chicks c; //.....(1)
public static void main(String[] args) {
new ChicksYack().go();
}
void go() {
c = new Chicks(); //........(2)
new Thread(new ChicksYack()).start();
new Thread(new ChicksYack()).start();
}
public void run() {
c.yack(Thread.currentThread().getId());
}
}
When i run this code, I am getting a Null Pointer Exception that I have not initialized variable c. But didn't i initialized it at line ....(2)? I am having trouble getting this concept. Does threading has a part to play in this exception?
Look at this line:
new Thread(new ChicksYack()).start();
^^^^^^^^^^^^^^^^
The attribute c of the newly created ChicksYack object is never initialized. In the go() method you only initialize c for the current (this) object.
That's why you get an NPE in the run() method. A good solution would be to initialize that variable in a default constructor for ChicksYack.
In the go() method, you're instantiating two new ChickYack objects, which have a null c. You should put the c = new Chicks() in your ChicksYack constructor.
Related
I am trying to access instance variable inside a Thread anonymous class . I am getting an error here saying to make it static . The point here is if i can access "this" keyword inside the anonymous class which treats it as its current object holder, then why is it not able to access the instance variables in a non static way .
public class AnonymousThreadDemo {
int num;
public AnonymousThreadDemo(int num) {
this.num = num;
}
public static void main(String[] args) {
Thread thread = new Thread() {
#Override
public void run() {
System.out.println("Anonymous " + num); // Why cant we access num instance variable
System.out.println("Anonymous " + this); // This can be accessed in a nonstatic way
}
};
thread.start();
}
}
num is a non static field, it belongs to a specific instance. You can not reference it in static main directly, because a static method can be called without creating an instance.
this is actually referencing thread, it is a local variable, when you execute run, the thread must have been created.
If you try reference AnonymousThreadDemo.this in main, you will get same result:
public static void main(String[] args) {
Thread thread = new Thread() {
#Override
public void run() {
System.out.println("Anonymous " + AnonymousThreadDemo.this); // compile error
}
};
thread.start();
}
This is ok, you can reference a local variable in local class:
public static void main(String[] args) {
int num = 0;
Thread thread = new Thread() {
#Override
public void run() {
System.out.println("Anonymous " + num);
}
};
thread.start();
}
This is ok, you can reference a non static local class field in its method:
public static void main(String[] args) {
Thread thread = new Thread() {
int num = 0;
#Override
public void run() {
System.out.println("Anonymous " + num);
}
};
thread.start();
}
Check this for more.
num is non static that means it will come after static main in the memory. Hence when main will try to point num it won't be available in the memory ie. It still won't be declared yet.
Why am I getting NullPointerException here
package Threads;
public class Test implements Runnable {
FF d;
public static void main(String[] args) {
new Test().go();
}
void go() {
System.out.println(Thread.currentThread());
d = new FF();
new Thread(new Test()).start();
new Thread(new Test()).start();
}
public void run() {
System.out.println(d);
System.out.println(Thread.currentThread());
d.chat(Thread.currentThread().getId());//RTE
}
}
class FF {
static long flag = 0;
void chat(long id) {
if(flag == 0) {
flag = id;
}
for(int x=1;x<3;x++) {
if(flag == id) {
System.out.println("Yo");
}else {
System.out.println("dude");
}
}
}
}
//can anybody explain why I am getting NullPointerException here.I though d reference variable was intialized in go() method but I think it has something to do when new Thread is created.
d is an instance field for class Test. Initializing it for one instance of Test does not make it initialized for all instances that are subsequently created. You have initialized this field in the go method of the instance you create in main. But after that, you create new instances of Test for which their field is not initialized yet:
new Thread(new Test()).start(); // d is not initialized for the new Test() object
new Thread(new Test()).start();
One solution is to initialize the field in the constructor:
public Test() {
d = new FF();
}
you're creating a new Test instance and thus d is not initialized (since the thread.start method doesn't call your go method but only the run method).
I want to use the the thread created on (say) instance x of class A in another class B.
I've stated my problems in better way in the form of comments below.
I have something like this:
Class A implements Runnable{
public static int num;
public void setNum(int i) { num = i; }
public int getNum() { return num; }
public void run(){
while(true){} //I want to keep this thread running continuously
}
}
Class B{
A a;
//I will call this method in class C to use the same instance of class A
public A getInstanceOfA() { return a; }
public static void main(String[] args){
a = new A();
Thread t = new Thread(a);
t.start();
a.setNum(5);
System.out.println(a.getNum()); //getting output as 5. Okay as Expected.
}
}
class C{
A a;
public static void main(String[] args){
a = getInstanceOfA();
System.out.println(a.getNum());
//Here I'm getting output 0 not 5 why? As Thread created on instance a is
//already running, and also I am using the same instance of class A
//so I should get the updated value 5, but getting 0. Why it is re-initializing num?
}
}
Please Help. Thanks.
I am not giving you the exact code but you should do it something like this.
Class B{
A a;
public B(){
initialize();
}
//I will call this method in class C to use the same instance of class A
public A getInstanceOfA() { return a; }
// this method should not be main
public void initialize{
a = new A();
Thread t = new Thread(a);
t.start();
a.setNum(5);
System.out.println(a.getNum()); //getting output as 5. Okay as Expected.
}
}
class C{
A a;
public static void main(String[] args){
B b = new B();
a = b.getInstanceOfA();
System.out.println(a.getNum());
//Here I'm getting output 0 not 5 why? As Thread created on instance a is
//already running, and also I am using the same instance of class A
//so I should get the updated value 5, but getting 0. Why it is re-initializing num?
}
}
You can also use Singleton
http://en.wikipedia.org/wiki/Singleton_pattern
Thread t = new Thread(new Runnable() { public void run() {} });
I'd like to create a thread this way. How can I pass parameters to the run method if possible at all?
Edit: To make my problem specific, consider the following code segment:
for (int i=0; i< threads.length; i++) {
threads[i] = new Thread(new Runnable() {public void run() {//Can I use the value of i in the method?}});
}
Based on Jon's answer it won't work, since i is not declared as final.
No, the run method never has any parameters. You'll need to put the initial state into the Runnable. If you're using an anonymous inner class, you can do that via a final local variable:
final int foo = 10; // Or whatever
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println(foo); // Prints 10
}
});
If you're writing a named class, add a field to the class and populate it in the constructor.
Alternatively, you may find the classes in java.util.concurrent help you more (ExecutorService etc) - it depends on what you're trying to do.
EDIT: To put the above into your context, you just need a final variable within the loop:
for (int i=0; i< threads.length; i++) {
final int foo = i;
threads[i] = new Thread(new Runnable() {
public void run() {
// Use foo here
}
});
}
You may create a custom thread object that accepts your parameter, for example :
public class IndexedThread implements Runnable {
private final int index;
public IndexedThread(int index) {
this.index = index;
}
public void run() {
// ...
}
}
Which could be used like this :
IndexedThread threads[] = new IndexedThread[N];
for (int i=0; i<threads.length; i++) {
threads[i] = new IndexedThread(i);
}
public class ThreadTest
{
public static Integer i = new Integer(0);
public static void main(String[] args) throws InterruptedException
{
ThreadTest threadTest = new ThreadTest();
Runnable odd = threadTest.new Numbers(1, "thread1");
Runnable even = threadTest.new Numbers(0, "thread2");
((Thread) odd).start();
((Thread) even).start();
}
class Numbers extends Thread
{
int reminder;
String threadName;
Numbers(int reminder, String threadName)
{
this.reminder = reminder;
this.threadName = threadName;
}
#Override
public void run()
{
while (i < 20)
{
synchronized (i)
{
if (i % 2 == reminder)
{
System.out.println(threadName + " : " + i);
i++;
i.notify();
}
else
{
try
{
i.wait();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
}
You can't synchronize on i because it changes during execution of your program.
Since Integer in Java is immutable, after executing i++ i will contain a reference to another object, not the object you have synchronized on. So, you can't call wait()/notify() on this new object, because these methods may be only called on the object you are synchronized on, otherwise you get IllegalMonitorStateException.
You need to synchronize on some other object that doesn't change during execution. For example, you may create a separate object for this purpose:
public class ThreadTest {
public static Integer i = new Integer(0);
public static Object lock = new Object();
...
class Numbers extends Thread {
...
#Override
public void run() {
...
synchronized (lock) {
...
lock.notify();
...
lock.wait();
...
}
}
}
}
This line:
i++;
is equivalent to:
i = i + 1;
which (due to autoboxing) becomes something like:
i = new Integer(i.intValue() + 1);
So, when you call i.notify() you are synchronized on the old i, not the new one.
I'd suggest changing i into an ordinary int variable, and create a separate object to synchronize on:
static int i = 0;
static Object iMonitor = new Object();
As documentation states the exception is thrown when
the current thread is not the owner of the object's monitor
It also states that
This method should only be called by a thread that is the owner of this object's monitor.
And this condition can be obtained by
By executing a synchronized instance method of that object.
By executing the body of a synchronized statement that synchronizes on the object.
For objects of type Class, by executing a synchronized static method of that class.
You could try calling the wait method from inside the class that uses i. This could be done by extending the class and writing two new methods for notify and wait..
You cannot put wait() and notify() in the same synchronized block because that will just cause a deadlock. Make sure only the wait and notify functions are wrapped with a synchronized block like this:
synchronized (i) {
i.wait(); // or i.notify();
}