In an interview I was asked to come up with an approach which will ensure that while thread T1 and T3 can access a method of a class, T2 cannot access the method.
I am unable to provide any solution to this. Could you please provide an example with an explanation?
I have later come up with the following solution. Is it efficient?
package JavaProgramming;
public class EligibleThread implements Runnable {
public void method1() {
System.out.println("Hello");
}
public static void main(String[] args) {
EligibleThread t1 = new EligibleThread();
EligibleThread t2 = new EligibleThread();
Thread t11 = new Thread(t1, "t1");
Thread t22 = new Thread(t2, "t2");
t11.start();
t22.start();
}
public void run() {
if (Thread.currentThread().getName() != "t2") {
method1();
} else{
try {
throw new Exception("Access is denied");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
You can use protected modifier, like following code. T1 can call aMethod() by extending Main class, but T2 can't call aMethod().
public class Main {
protected void aMethod() {
}
}
class T1 extends Main implements Runnable{
#Override
public void run() {
aMethod();
}
}
class T2 implements Runnable{
#Override
public void run() {
// here can't call Main.aMethod()
}
}
Related
I have this code:
public class UsbDrive extends HardDrive {
private Date lastUpdate;
private void updateDate() {
lastUpdate = new Date();
}
public synchronized void cutAndPaste(UsbDrive other, int originAddress, int destAddress) {
byte[] data = read(originAddress);
boolean success = other.write(data, destAddress);
if (success) {
erase(originAddress);
updateDate();
} else {
throw new RuntimeException("Write failed!");
}
}
}
class HardDrive {
...
public synchronized byte[] read(int address) {...}
public synchronized boolean write(byte[] data, int address) {...}
public synchronized void erase(int address) {...}
...
I'm trying to simulate a deadlock
public class Main {
private static UsbDrive usb1 = new UsbDrive();
private static UsbDrive usb2 = new UsbDrive();
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new ThreadA());
Thread thread2 = new Thread(new ThreadB());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
static class ThreadA implements Runnable {
#Override
public void run() {
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
synchronized (usb1) {
usb1.cutAndPaste(usb2, 1, 2);
}
}
}
static class ThreadB implements Runnable {
#Override
public void run() {
synchronized (usb2) {
usb2.cutAndPaste(usb1, 1, 2);
}
}
}
}
However deadlock doesn't happen - why? ThreadA calls method cutAndPaste() locked on usb1, while inside that method write() is called which is locked on usb2
Shouldn't deadlock occur?
How should I change the code to trigger deadlock?
I get this output:
reading data
Erasing data
reading data
Erasing data
It is a race condition that decides whether the deadlock happens or not as far as I can see, one good option to make the deadlock more likely to happen is a loop, but an easier option might be to insert Thread.sleep(5000); between byte[] data = read(originAddress); and boolean success = other.write(data, destAddress); in UsbDrive::cutAndPaste. EDIT: And remove the existing Thread.sleep(5000);.
EDIT: Clarified answer.
EDIT2: I just ran the code with the changes, and it indeed induces a deadlock now:
import java.util.Date;
public class Main {
private static UsbDrive usb1 = new UsbDrive();
private static UsbDrive usb2 = new UsbDrive();
public static void main(String[] args) throws Exception {
Thread thread1 = new Thread(new ThreadA());
Thread thread2 = new Thread(new ThreadB());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
static class ThreadA implements Runnable {
#Override
public void run() {
synchronized (usb1) {
usb1.cutAndPaste(usb2, 1, 2);
}
}
}
static class ThreadB implements Runnable {
#Override
public void run() {
synchronized (usb2) {
usb2.cutAndPaste(usb1, 1, 2);
}
}
}
}
class UsbDrive extends HardDrive {
private Date lastUpdate;
private void updateDate() {
lastUpdate = new Date();
}
public synchronized void cutAndPaste(UsbDrive other, int originAddress, int destAddress) {
byte[] data = read(originAddress);
try {
Thread.sleep(5000);
}
catch (Exception e) {
e.printStackTrace();
}
boolean success = other.write(data, destAddress);
if (success) {
erase(originAddress);
updateDate();
} else {
throw new RuntimeException("Write failed!");
}
}
}
class HardDrive {
public synchronized byte[] read(int address) {return new byte[]{};}
public synchronized boolean write(byte[] data, int address) {return true;}
public synchronized void erase(int address) {}
}
I'm having a trouble with Runnable and Thread implementations. I have this abstract class, that can not be modified:
abstract class Ordenador {
...
protected Ordenador(String nombre, int[] array) {
...
}
protected void escribir() {
...
}
protected abstract void ordenar();
}
And this sort algorithm that inherit from the class above and implements the run() method, which call the sorting one.
class Burbuja extends Ordenador implements Runnable {
protected Burbuja(String nombre, int[] array) {
super(nombre, array);
}
protected void ordenar() {
....
}
public void esperar() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public void run() {
this.ordenar();
}
}
Finally I have my main class that creates a random array and create a new Burbuja object that sort the array. The problem is that when calling b.join() the array stay the same so de ordenar() method doesn't get called.
class Aplicacion {
public static void main(String[] args) {
...
Burbuja burbuja = new Burbuja("Burbuja", array);
Thread b = new Thread(burbuja);
...
try {
b.join();
s.join();
... more sorting algorithms...
} catch (Exception ex) {
ex.printStackTrace();
System.exit(-1);
}
System.out.println("");
burbuja.escribir();
}
}
I tried modificating some parts of the code but doesn't work neither.
You have to call the start() method on your thread object
https://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html
Your Thread b = new Thread(burbuja); is right, but you forget to call the start method, b.start();
I have a singleton class which is also Runnable (and Observable). When I'm trying to start the thread from main, it does not create a new thread and gets stuck in the main loop.
public class A extends Observable implements Runnable
{
private static A instance = null;
private A() {
}
public static A getInstance() {
if(instance == null) {
instance = new A();
}
return instance;
}
#Override
public void run()
{
while (true) {
System.out.print("\nSleeping");
// sleep
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.print("\n[Error]");
}
}
}
}
and the main class:
Thread thread = new Thread(A.getInstance());
thread.run();
System.out.print("\nAfter...");
I cant see the "After" log, just the "Sleeping" in a loop. Why?
You're calling run(), instead of start().
suppose we have these classes and read the comments
class Work {
void doWork(){ }
void commit(){}
}
class MyRunable implements Runnable {
run(){
Work work=new Work();
work.doWork();
//i can't write work.commit() here, because sometimes i want Thread runs both methods
//and sometimes runs only doWork()
}
}
class Tasks{
main(){
MyRunable myRunable=new MyRunable();
Thread t=new Thread(myRunable);
t.start();
//suppose now i need to call commit() method by the same thread (t)
//how can i do that
}
}
also i don't want to use constructor to determine if i want to call both method or not
You could try using a thread pool with a single thread and keep enqueuing methods as needed:
class Tasks {
public static void main(String[] args) {
ExecutorService exec = Executors.newSingleThreadExecutor();
final Work work = new Work();
exec.submit(new Runnable() {
public void run() {
work.doWork();
}
});
// later
exec.submit(new Runnable() {
public void run() {
work.commit();
}
});
}
}
This way, both methods will be executed in a sequence by the same thread, but separately.
Add parameter to your class MyRunnable. Call this parameter "runingMode". It could be an enum:
enum RunningMode {
DO_WORK {
public void work(Work work) {
work.doWork();
}
},
COMMIT {
public void work(Work work) {
work.commit();
}
};
public abstract void work();
}
Now your class MyRunnable should have list of modes:
class MyRunable implements Runnable {
private Collection<RunningMode> modes;
MyRunable(Collection<RunningMode> modes) {
this.modes = modes;
}
}
Implement run() method as following:
Work work=new Work();
for (RunningMode mode : modes) {
mode.work(work);
}
work.doWork();
Create instance of your class passing to it the mode you currently need:
MyRunable myRunable=new MyRunable(Arrays.asList(RunningMode.DO_WORK, RunningMode.COMMIT));
You could use an anonymous class.
final boolean condition = ...
Thread t = new Thread(new Runnable() {
public void run() {
Work work=new Work();
work.doWork();
if(condition)
work.commit();
}});
t.start();
I believe variables used in static main method should be also static as well.
The problem is that I cannot use this in this method at all. If I remember correctly, I have to initiate thread with commnad myThread = new ThreaD(this).
The below codes produces an error because I used this in thread initiation.
What have I done wrong here?
package app;
public class Server implements Runnable{
static Thread myThread;
public void run() {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
System.out.println("Good morning");
myThread = new Thread(this);
}
}
You can't use this because main is a static method, this refers to the current instance and there is none. You can create a Runnable object that you can pass into the thread:
myThread = new Thread(new Server());
myThread.start();
That will cause whatever you put in the Server class' run method to be executed by myThread.
There are two separate concepts here, the Thread and the Runnable. The Runnable specifies what work needs to be done, the Thread is the mechanism that executes the Runnable. Although Thread has a run method that you can extend, you can ignore that and use a separate Runnable.
Change new Thread(this) to new Thread(new Server()):
package app;
public class Server implements Runnable{
static Thread myThread;
public void run() {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
System.out.println("Good morning");
myThread = new Thread(new Server());
}
}
class SimpleThread extends Thread {
public SimpleThread(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i + " thread: " + getName());
try {
sleep((int)(Math.random() * 1000));
} catch (InterruptedException e) {}
}
System.out.println("DONE! thread: " + getName());
}
}
class TwoThreadsTest {
public static void main (String[] args) {
new SimpleThread("test1").start();
new SimpleThread("test2").start();
}
}