1. Java / Говнокод #12010

    +95

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    import java.io.PrintStream;
    import java.util.concurrent.atomic.AtomicBoolean;
    
    public final class ShredingerCat
    extends AtomicBoolean
    {
    	static final PrintStream o=System.out;
    	static final long initMsec=System.currentTimeMillis ();
    	
    	public static final ShredingerCat	INSTANCE = new ShredingerCat();
    	private ShredingerCat ()
    	{
    		set ( false );
    		o.println ( "Construct SingleBool" );
    	}
    	public final
    	void criticalSection(){
    		synchronized (this) {
    			pr ( "Enter critical section" );
    			ShredingerCat.sl ( 5 );
    			
    			pr ( "Cat is " +(
    					get() 
    					? "dead"
    					: "alive"
    				)
    			);
    			sl(100);
    			pr ( "Exit critical section" );
    		}
    		
    	}
    	// ===================== HELPER STUFF ========================
    
    	static void pr(String s){
    		o.println ( s+(
    			System.currentTimeMillis ()- initMsec
    		));
    	}
    	static void sl(long l){
    		try {
    			Thread.sleep ( l );
    		}catch (InterruptedException e) {
    		}
    	}
    	
    
    
    }

    Обсуждение #11989 безопасных публикаций, конструкторов и синглтонов вдохновило меня на создание этого примера.
    Суть: есть кот-синглтон. Он как вы видите защищен со всех сторон finalами, приправленое к тому же Atomicом.
    Задание на серебряную медаль - сделать так чтобы 2 последовательных вызова toString() вывели Dead и Alive. Объект не должен меняться.
    Задание на золотую медаль: необходимо получить примерно такой вывод:
    Enter critical section0
    Enter critical section0
    Cat is alive16
    Cat is dead16
    Exit critical section110
    Exit critical section110

    За использование рефлексии и прочих unsafe - немедленная дисквалификация и бан модератором.
    Решение будет чуть позже. Отдельным постом.

    Запостил: 3.14159265, 26 Октября 2012

    Комментарии (24) RSS

    • Блин. Забыл сам toString()
      public String toString ()
      	{
      		return get() 
      		? "dead"
      		: "alive";
      	}

      Потратил полтора часа на этот иезуитский говно-пример. Если кому надо - дам подсказки.
      Но уверяю вас - это знатнейшее говно.
      Ответить
    • Надеюсь, что решение будет подробным, потому что не все могут в жабу.
      Ответить
    • public class AtomicBoolean
      implements Serializable

      К сожалению, синглетон без readResolve - хреновый синглетон
      Ответить
      • Браво! Раскусил меня.
        Хотя вот когда я постил - вся надежда была только на тебя, честно.
        Ответить
    • > Задание на серебряную медаль - сделать так чтобы 2 последовательных вызова toString() вывели Dead и Alive. Объект не должен меняться.

      Вот такой ответ сойдет?
      class Main extends Thread{
          static final ShredingerCat cat = ShredingerCat.INSTANCE;
          public void run() {
              System.out.println(cat.toString());
              System.out.println(cat.toString());
          }
          public static void main(String[] args) throws Throwable {
              Thread t1 = new Main();
              t1.start();
              while (true) {
                  cat.set(true);
                  cat.set(false);
              }
          }
      }
      Ответить
      • >Объект не должен меняться.
        Объект меняется в другом треде.
        Ответить
    • Короче вот решение:
      http://ideone.com/KYkqFp
      Суть - сериализация использует еще один свой, неявный конструктор. И с помощью него можно создать сколько угодно таких объектов.
      public class Main
      {
          static PrintStream o=System.out;
      	public static void main ( String[] args )
      	{
      		ShredingerCat.INSTANCE.set ( true );
      		ShredingerCat fals = cheatyCopy ( ShredingerCat.INSTANCE );
      		fals.set ( false );
      		o.println ( "Eq:"+(fals == ShredingerCat.INSTANCE) );
      		o.println ( "F:"+fals );
      		o.println ( "SingleBool:"+ShredingerCat.INSTANCE);
      		new Thread(){
      			public void run (){
      				ShredingerCat.INSTANCE.criticalSection ();
      			}
      		}.start ();
      		fals.criticalSection ();
      	}
      
      	@SuppressWarnings ("unchecked")
      	static public <T> T cheatyCopy ( Object obj )
      	{
              try {
                  ByteArrayOutputStream bos =
                      new ByteArrayOutputStream();
                  new ObjectOutputStream(bos).writeObject(obj);
                  ByteArrayInputStream bin =
                      new ByteArrayInputStream(bos.toByteArray());
                  return (T) new ObjectInputStream(bin).readObject();
              } catch (Exception e) {
                  throw new IllegalArgumentException(e);
              }
      	}
      }
      Ответить
      • (Звучат апплодисменты) Ловкость рук, и никакого обмана ;)

        Получается, если класс заимплементил Serializable, то все его потомки до седьмого колена автоматом становятся сериализуемыми (если не перекроют readObject и readResolve и не выбросят оттуда исключение)?

        P.S. Отвечу сам себе: All subtypes of a serializable class are themselves serializable.
        Ответить
        • Ну если бы никто не смог решить то была заготовлена каверзная подсказка
          private Object mutex=new Object();
          ..
          synchronized (mutex) {
          Добавление такого кода делает класс безопасным.

          Хотя всё дело конечно не в synchronized, а в transient.
          Ответить
          • > Хотя всё дело конечно не в synchronized, а в transient.
            Угу, а sychronized(mutex) красиво спрятало бы истинную причину, по которой код становится безопасным (поломка сериализатора из-за не transient поля, класс которого не умеет в сериализацию)...
            Ответить
    • Какие хитросплетения в жабе то...
      Ответить
      • Ну так объектно-ориентированные технологии значительно упрощают разработку, Тарас подтвердит
        Ответить
        • Конечно. Ведь эти паттерны разработали для того, чтобы программы были читаемыми и расширяемыми. Самые успешные программисты используют ООП, исключения и ГЦ.
          Ответить
          • А ты ещё не пришел к успеху? Не пользуешься ООП, исключениями, паттернами, кодогенерацией и ГЦ?
            Ответить
        • Помню как тут кто-то смеялся с Тараса что он пишет руками сериализацию (конечно та сериализация вроде была жутко убогой).
          Но мне почему-то было не смешно.
          Ответить
          • Я бы тоже смеяться не стал. Сам сейчас пишу кастомную маршализацию для взаимодействия с кодом, написанном на другом языке программирования.
            Ответить
            • Отож. Хотя wsdl для таких делов есть конечно.
              Вспомнился случай - дали мне wsdl, который сам по себе превращает передаваемые данные в xml.
              Подложил я значит заглушки - объекты.
              И смотрю каждый объект с одним методом, и метод этот возвращает, возвращает значит сюрприз!
              XML с обычной структурой поле - значение.
              Вот такое говно .
              Ответить
              • Для высоконагруженных сетевых протоколов wsdl не катит. На другом конце c++ и байтолюбство.
                Ответить
                • google protocol buffers не подходят к этой задаче?
                  Ответить
                  • 1. Его нужно подключать с обоих сторон, а другую сторону желательно не трогать
                    2. Там не так уж много структур, чтобы поднимать protobuf, проще описать руками, протокол довольно простой, используется всего несколько типов данных
                    3. Структура протокола очень вариативна. Первые байты - номер команды. В зависимости от номера команды могут быть разные аргументы. Не уверен, насколько protobuf хорош при описании подобных структур (изменять которые крайне нежелательно).

                    По мне тут проще использовать фабрику команд с ручной маршализацией аргументов.
                    Ответить
                    • > Там не так уж много структур, чтобы поднимать protobuf
                      > Структура протокола очень вариативна.
                      Т.е. я так понимаю, что там несколько достаточно больших структур, у которых в зависимости от типа команды активны то одни то другие поля? Здесь бы, наверное, подошел флаг optional.

                      > другую сторону желательно не трогать
                      > протокол довольно простой
                      Тогда действительно не стоит заморачиваться с протобуферами, согласен.
                      Ответить
    • Schroedinger
      *fix
      Ответить
      • Schrödinger
        fix
        Ответить
        • Кстати у меня нормально работает код после такого переименования, а Ideone не понимает неаскишных имен классов ;(
          SchrödingerCat cat = new SchrödingerCat();
          Ответить

    Добавить комментарий