"This is a question very dealt in forums. I personally don't like the "static" declaration, since it implies in one hand that you can use methods from a class without the need to declare objects from the very class, and in the other hand the direct sharing of attributes for all the instances of a class.
Both behaviours are, in my opinion, a bad practice of OOP, but allowed in JAVA (like a lot of other things).
" My teacher.

What do you think about the "static" declaration?

Apart from the opinions that anyone might have with this declaration, I am in this situation:
If you have dealt with Concurrent Java you might know that it's very common to use the example of Producer-Consumer.

The following code I show you, contains the integer static variable "cake" and a static 'lock' object for the Synchronized block.

I think that obviously the question is: If using "static" is supposed to be (for many people) a bad practice, is there any alternative way to solve these kind of problems without using "static"?

Code:
/*

 CONSUMER:

 - If there's any cake = I eat 1 cake.

 - Otherwise ... = Wake up the cook, sleep consumer.

 COOK:

 - I sleep while waiting to be called by a consumer/client.

 - If I produce 10 pieces of cake, I sleep.

 */

public class Main implements Runnable {

 

     private boolean consumer;

     private static int cake=0;

     private static Object lock = new Object();

    

     public Main (boolean consumer) {

          this.consumer=consumer;

     }

 

     public void run() {

          while(true) {

                if(consumer) {

                     consume();

                }else {

                     cook();

                }

          }

     }

    

     private void consume() {

          synchronized(lock) { //Lock

                if(cake>0) { //If there are any cakes...

                     cake--; //Eat a cake.

                     System.out.println("There are "+cake+" pieces of cake left.");

                     try {

                          Thread.sleep(1000);

                     } catch (InterruptedException e) {

                          e.printStackTrace();

                     }

                }else { //If there are no cakes.

                     lock.notifyAll(); //Wake up the cook who was waiting (open Lock, let him cook)

                     try {

                          lock.wait(); //Sleep the consumer (until being awakened)

                     } catch (InterruptedException e) {

                          e.printStackTrace();

                     }

                }

          }

     }

    

     private void cook() {

          synchronized (lock) {

                if(cake==0) {

                     cake=10; //Cook 10 pieces of cake

                     System.out.println("I'm the cook and there are "+cake+" pieces of cake left.");

                     lock.notifyAll(); //Hey! The cakes are ready! Ok!

                } try {

                     lock.wait(); //sleep the Cook

                }catch(Exception e) {}

          }

     }

    

     public static void main(String[] args) {

          int threadsNumber = 11;

         

          Thread[] thread = new Thread[threadsNumber];

         

          for(int i=0; i<thread.length; i++) {

                Runnable runnable = null;

               

                if(i !=0) {

                     runnable = new Main(true);

                }else {

                     runnable = new Main(false);

                }

               

                thread[i] = new Thread(runnable);

                thread[i].start();

          }

         

          for(int i=0; i<thread.length; i++) {

                try {

                     thread[i].join();

                }catch(Exception e) {}

          }

     }

}

Thank you!