題目:啓動三個線程,使他們有序的交替的打印0-100java
最開始我想到的是bash
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadTest3 implements Runnable {
private static final AtomicInteger atomicInteger = new AtomicInteger(0);
private int i = 0;
public static void main(String[] args) {
ThreadTest3 t = new ThreadTest3();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
Thread t3 = new Thread(t);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
@Override
public void run() {
while (true){
if(atomicInteger.get() <100){
System.out.println(Thread.currentThread().getName() + "_" + atomicInteger.getAndIncrement());
}else {
break;
}
}
}
}
複製代碼
結果出來的是ide
t1_0
t1_2
t1_3
t1_4
t1_5
t2_1
t2_7
t1_6
t1_9
t1_10
t1_11
t1_12
t1_13
t1_14
t1_15
t1_16
t1_17
t1_18
t2_8
......
複製代碼
一看就是既沒有交替有沒有有序ui
交替的話,須要一個線程執行完成以後,放棄cpu的資源,想到的就是wait方法,執行wait以前須要執行notify把其餘的線程先喚醒this
因而就有了第二個版本atom
public class ThreadTest7 extends Thread {
private Object lock;
private static int i;
public ThreadTest7(Object lock) {
this.lock = lock;
}
@Override
public void run() {
while (true) {
synchronized (this) {
notify();
if (i < 100) {
System.out.println(Thread.currentThread().getName() + "_" + i);
i++;
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new ThreadTest7(lock);
Thread t2 = new ThreadTest7(lock);
Thread t3 = new ThreadTest7(lock);
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
複製代碼
輸出結果爲:交替是交替了,可是沒有打完spa
t1_0
t2_1
t3_2
沒有而後了
複製代碼
查了網上的資料,線程
public class ThreadTest4 implements Runnable{
int i = 1;
public static void main(String[] args) {
ThreadTest4 t = new ThreadTest4();
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
t1.setName("線程1");
t2.setName("線程2");
t1.start();t2.start();
}
public void run() {
while (true) {
synchronized (this) {
// 先喚醒另一個線程
notify();
if (i <= 100) {
System.out.println(this.getClass().getName() + "_" + this.hashCode());
System.out.println(Thread.currentThread().getName() + ":"+ i);
i++;
try {
// 打印完以後,釋放資源,等待下次被喚醒
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
break;
}
}
}
}
}
複製代碼
結果果真能夠交替有序的把數字打印出來了。code
Runnable和Thread建立線程的區別
Runnable r = new Runnable();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1和t2會共享到r中的屬性,好比上例中的i,以及this也是同一個Runnable t.資源
這三個方法都是Object的方法,
方法 | 註釋 |
---|---|
notify | Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened |
notifyAll | Wakes up all threads that are waiting on this object's monitor. A thread waits on an object's monitor by calling one of the {@code wait} methods. |
wait | Causes the current thread to wait until another thread invokes the {@link java.lang.Object#notify()} method or the{@link java.lang.Object#notifyAll()} method for this object. |
notify和notifyAll起做用的前提是,他們須要獲取同一個object實例的monitor
(synchronized的實現原理,synchronized修飾的代碼塊編譯完了以後,實際上是monitorenter和monitorexit兩個指令包的,要否則沒法喚醒其餘的線程,就像個人ThreadTest7。
因此這三個方法必須放在同步代碼塊中
,當線程執行wait()時,會把當前的鎖釋放,而後讓出CPU,進入等待狀態。
按照上面的概念,因此若是要使用Thread不用Runnable的話,可使用下面的方式
public class ThreadTest6 extends Thread {
private static Object lock = new Object();
private static int i;
@Override
public void run() {
while (true) {
synchronized (lock) {
lock.notify();
if (i < 100) {
System.out.println(Thread.currentThread().getName() + "_" + i);
i++;
}
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Thread t1 = new ThreadTest6();
Thread t2 = new ThreadTest6();
Thread t3 = new ThreadTest6();
t1.setName("t1");
t2.setName("t2");
t3.setName("t3");
t1.start();
t2.start();
t3.start();
}
}
複製代碼