面接は必ず聞きますJavaマルチスレッドでは、二つのスレッドが交互に実行され、一つは偶数、一つは奇数を出力します。
4173 ワード
前言
スレ主さんは今日面でこの問題を見ました。面白いです。小さなテーマはマルチスレッドに対する考えが多いです。ほとんどの学生はsynchronizedを使って実現します。ビルの主人は今日他の二つの最適化を持ってきて、面接の時、群雄を傲視します。
第一種類のsynchronized
しかし、このように書くと、面接官はきっと不満です。ビル主はより良い実現を紹介します。
CASを使って実現します
このようにして、synchronizedによるコンテキストスイッチングによる損失が解消され、性能がより良い。面接の時、このように書いたら、面接官はきっと満足すると信じています。
でも、もっと性能がいいのがあります。
volatileを使う
ここに来て、面接の時にこのように書いたら、オフは遠くないですよ。ははは?
タマゴは文字列をどうやって反転しますか?
はい、面接が成功しますように。
転載先:https://www.cnblogs.com/stateis0/p/9091254.html
スレ主さんは今日面でこの問題を見ました。面白いです。小さなテーマはマルチスレッドに対する考えが多いです。ほとんどの学生はsynchronizedを使って実現します。ビルの主人は今日他の二つの最適化を持ってきて、面接の時、群雄を傲視します。
第一種類のsynchronized
class ThreadPrintDemo2 {
public static void main(String[] args) {
final ThreadPrintDemo2 demo2 = new ThreadPrintDemo2();
Thread t1 = new Thread(demo2::print1);
Thread t2 = new Thread(demo2::print2);
t1.start();
t2.start();
}
public synchronized void print2() {
for (int i = 1; i <= 100; i += 2) {
System.out.println(i);
this.notify();
try {
this.wait();
Thread.sleep(100);//
} catch (InterruptedException e) {
// NO
}
}
}
public synchronized void print1() {
for (int i = 0; i <= 100; i += 2) {
System.out.println(i);
this.notify();
try {
this.wait();
Thread.sleep(100);//
} catch (InterruptedException e) {
// NO
}
}
}
}
synchronized同期の2つの方法により、毎回一つのスレッドだけが進入し、一つの数を印刷するごとにロックを解除し、もう一つのスレッドが進入し、ロックを取って、印刷して、もう一つのスレッドを起動し、自分を吊るします。繰り返して、最も基本的な印刷機能を実現しました。しかし、このように書くと、面接官はきっと不満です。ビル主はより良い実現を紹介します。
CASを使って実現します
public class ThreadPrintDemo {
static AtomicInteger cxsNum = new AtomicInteger(0);
static volatile boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (; 100 > cxsNum.get(); ) {
if (!flag && (cxsNum.get() == 0 || cxsNum.incrementAndGet() % 2 == 0)) {
try {
Thread.sleep(100);//
} catch (InterruptedException e) {
//NO
}
System.out.println(cxsNum.get());
flag = true;
}
}
}
);
Thread t2 = new Thread(() -> {
for (; 100 > cxsNum.get(); ) {
if (flag && (cxsNum.incrementAndGet() % 2 != 0)) {
try {
Thread.sleep(100);//
} catch (InterruptedException e) {
//NO
}
System.out.println(cxsNum.get());
flag = false;
}
}
}
);
t1.start();
t2.start();
}
}
私たちはCASを使うことによって、スレッドの文脈の切り替えを避けます。そして、volatileのbootlean変数を使って、可視性の問題がないことを保証します。覚えてください。このflagsは必ずvolatileのものであれば、そうでなければ、あなたのプログラムが実行されても大丈夫ですが、最終的には必ず問題が発生します。そして面接官はすぐにあなたを軽蔑します。このようにして、synchronizedによるコンテキストスイッチングによる損失が解消され、性能がより良い。面接の時、このように書いたら、面接官はきっと満足すると信じています。
でも、もっと性能がいいのがあります。
volatileを使う
class ThreadPrintDemo3{
static volatile int num = 0;
static volatile boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (; 100 > num; ) {
if (!flag && (num == 0 || ++num % 2 == 0)) {
try {
Thread.sleep(100);//
} catch (InterruptedException e) {
//NO
}
System.out.println(num);
flag = true;
}
}
}
);
Thread t2 = new Thread(() -> {
for (; 100 > num; ) {
if (flag && (++num % 2 != 0)) {
try {
Thread.sleep(100);//
} catch (InterruptedException e) {
//NO
}
System.out.println(num);
flag = false;
}
}
}
);
t1.start();
t2.start();
}
}
私たちはCAS変数の代わりにvolatile変数を使って、CASを使った消耗を軽減します。ここで+numは原子ではないが、flags変数の制御があるので邪魔しないように注意してください。numはvolatileでなければなりません。そうでなければ、視認性の問題を引き起こします。ここに来て、面接の時にこのように書いたら、オフは遠くないですよ。ははは?
タマゴは文字列をどうやって反転しますか?
class ReverseDemo {
public static void main(String[] args) {
String test = "abcdefg";
System.out.println(new StringBuilder(test).reverse());
char[] arr = test.toCharArray();
for (int i = arr.length - 1; i >= 0; i--) {
System.out.print(arr[i]);
}
}
}
これは比較的簡単です。二つの方法、一つはStringBuiderのreverse方法で、一つは配列に変換して自分で印刷します。自己転換性能がより良く、reverse方法の内部ステップがより多くなります。はい、面接が成功しますように。
転載先:https://www.cnblogs.com/stateis0/p/9091254.html