みなさんこんにちは!
最もハードコアなJava会議の1つであるJPoint 2019は終了し、7回目の開催となり、いつものように出席記録を破りました。
OdnoklassnikiはすべてのJPoint会議に参加しました。 2013年以来、私たちはJPointを積極的にサポートしており、スタンドでは参加者のためにさまざまなJava知識テスト活動を組織しています。 今年は、主要なOK.ru開発者からの有名な「解決できない」タスクがありました。 質問に正しく答えた会議参加者は賞品を受け取りました。
公平に言えば、私たちが配布したタスクを含む600のリーフレットのうち、100未満が返され、平均スコアは約0.25であると言わなければなりません。
最良の解決策は、5点満点の4点を採点することでした。
強みをテストできるように、タスクとそのソリューションを公開しています。
ビーツビー
この問題は、回答に合格した40%によって解決されました。
Michaelは
BitSet
スレッドセーフな類似物を作成します。
setBit()
メソッドの実装を追加します。
簡単にするために、
BitSet
サイズは一定と見なすことができます。
public class ConcurrentBitSet { private final AtomicLongArray bits; public ConcurrentBitSet(int size) { assert size >= 0; int words = (size + 63) / 64; bits = new AtomicLongArray(words); } public void setBit(int index) { // TODO: Implement me! } }
解決策
Java 8で使用可能な
/
を使用した実装は、
ようになります。
古き
の実装は似ています:
updateAndGet()
/
getAndUpdate()
を使用した実装は、
updateAndGet()
ようになります。
public void setBit(int index) { int word = index >> 6; long mask = 1L << index; bits.updateAndGet(word, value -> value | mask); }
古き
compareAndSet()
の実装は似ています:
public void setBit(int index) { int word = index >> 6; long mask = 1L << index; long oldValue; long newValue; do { oldValue = bits.get(word); newValue = oldValue | mask; } while (!bits.compareAndSet(word, oldValue, newValue)); }
列挙型が同じではありません
この問題は、回答に合格した45%によって解決されました。
Tatianaは、2つのオブジェクトが同じ
enum
定数であるかどうかを確認したいと考えています。 彼女は何を考慮しなかったのですか?
boolean sameEnum(Object o1, Object o2) { return o1.getClass().isEnum() && o1.getClass() == o2.getClass(); }
解決策
ヒントは、 たとえばEnum.compareTo()で使用されるEnum.getDeclaringClass()メソッドのドキュメントにあります
空でないボディを持つ列挙型定数の場合、中間クラスが作成されるため、正しい答えは次のようになります。
Enum.compareTo():
public final Class<E> getDeclaringClass() { Class<?> clazz = getClass(); Class<?> zuper = clazz.getSuperclass(); return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper; }
空でないボディを持つ列挙型定数の場合、中間クラスが作成されるため、正しい答えは次のようになります。
boolean sameEnum(Object o1, Object o2) { return o1 instanceof Enum && o2 instanceof Enum && ((Enum) o1).getDeclaringClass() == ((Enum) o2).getDeclaringClass(); }
未コンパイルのリンク
この問題は、回答に合格した42%によって解決されました。
以下のインターフェースが利用可能です:
interface Link<T> { T next(); }
getTail()
)メソッドの署名(ただし、本文ではない)を変更して、エラーや警告なしにコードがコンパイルされるようにします。
Link getTail(Link head) { if (head.next() == null) { return head; } return getTail(head.next()); }
解決策
正解は3つだけです。
逆説的に思えるかもしれませんが、このような署名はJavaコンパイラにとっては強すぎます。
<T extends Link<T>> Link<T> getTail(Link<T> head) <T extends Link<T>> Link<T> getTail(T head) <T extends Link<T>> T getTail(T head)
逆説的に思えるかもしれませんが、このような署名はJavaコンパイラにとっては強すぎます。
<T extends Link<T>> T getTail(Link<T> head)
メッセンジャー
この問題は、回答に合格した14%によって解決されました。
Kostyaはメッセージングアプリケーションを開発しています。 ネットワーク経由でメッセージを送信する方法にエラーがあることを示します。
void send(SocketChannel ch, String message) throws IOException { byte[] bytes = message.getBytes(); ByteBuffer header = ByteBuffer.allocate(4); header.putInt(bytes.length); ch.write(header); ch.write(ByteBuffer.wrap(bytes)); }
解決策
このコードには少なくとも3つのエラーがあります。
これは、修正バージョンのように見える場合があります。
- String.getBytes()はデフォルトのプラットフォームエンコーディングを使用します 。これはVMの開始時に決定され、ロケールとOSエンコーディングに依存するため、 Charsetを明示的に渡す方が適切です
- 書き込み後、
ByteBuffer
から読み取る前に、 flip() / rewind() / position(0)メソッドを呼び出す必要があります。そうしないと、SocketChannel
何も書き込まれません(黙って!)
- 最後に、 SocketChannel.write()メソッドは正常に書き込まれたバイト数を返し、バッファー全体が1回の呼び出しで書き込まれることを保証しません
これは、修正バージョンのように見える場合があります。
void send(SocketChannel ch, String message) throws IOException { byte[] bytes = message.getBytes(StandardCharsets.UTF_8); ByteBuffer header = ByteBuffer.allocate(4); header.putInt(bytes.length); header.flip(); while (header.hasRemaining()) { ch.write(header); } ByteBuffer body = ByteBuffer.wrap(bytes); while (body.hasRemaining()) { ch.write(body); } }
コンテナ内のJava
この問題は、回答に合格した7.5%によって解決されました。
コンテナに割り当てられたメモリ制限を超えてLinux OSがJavaプロセスを強制終了しないようにするために、JVMのどのパラメータをAlexeiに規定する必要がありますか?
-
-Xmx
-
-XX:MaxMetaspaceSize
-
-XX:ReservedCodeCacheSize
-
-XX:+UseContainerSupport
-
-XX:MaxRAMPercentage
- JVMメモリを制限することはできません
解決策
Javaプロセスによって消費されるメモリは、ヒップ、メタスペース、およびコードキャッシュに限定されるものではありません。 他の多くのJVM構造もメモリを占有し、それらのすべてが設定によって規制されているわけではありません。 仮想Javaマシンに加えて、ネイティブメモリはJavaクラスライブラリとDirect ByteBuffersおよびMapped ByteBuffersを介したユーザーコードによって割り当てられます。
パラメーターと
は、ヒープのサイズにのみ影響します。 したがって、JVMフラグのみを使用して制限を超えないようにする方法は保証されておらず、最後の答えは正しいものになります。 プロセスによるJavaメモリの使用の詳細については、Joker 2018に関するAndrei Panginのレポート「シェルフ上のJavaプロセスメモリ」を参照してください。
UseContainerSupport
パラメーターと
MaxRAMPercentage
は、ヒープのサイズにのみ影響します。 したがって、JVMフラグのみを使用して制限を超えないようにする方法は保証されておらず、最後の答えは正しいものになります。 プロセスによるJavaメモリの使用の詳細については、Joker 2018に関するAndrei Panginのレポート「シェルフ上のJavaプロセスメモリ」を参照してください。