線程間通訊:其實就是多個線程在操作同一個資源,但是操作的動作不同。
class Res
{
String name;
String sex;
}
class Input implements Runnable
{
private Res r;
private int x = 0;
Input(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
synchronized (r)
{
if (x==0)
{
r.name = "mike";
r.sex = "man";
}
else
{
r.name = "麗麗";
r.sex = "女女女女女女";
}
x = (x+1)%2;
}
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
synchronized (r)
{
System.out.println(r.name+"....."+r.sex);
}
}
}
}
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
//輸出正常
mike.....man
mike.....man
mike.....man
麗麗.....女女女女女女
麗麗.....女女女女女女
麗麗.....女女女女女女
wait();notify();notifyAll();都使用在同步中,因為要對持有監視器(鎖)的線程操作。所以要使用在同步中,因為只有同步才具有鎖。
為什么這些操作線程的方法要定義object類中呢?
因為這些方法在操作同步中線程時,都必須要標識他們所操作線程持有的鎖,只有同一個鎖上的被等待線程,可以被同一個鎖上notify喚醒。不可以對不同鎖中的線程進行喚醒。
也就是說,等待和喚醒必須是同一個鎖。
而鎖可以是任意對象,所以可以被任意對象調用的方法定義Object類中。
class Res
{
String name;
String sex;
boolean flag = false;
}
class Input implements Runnable
{
private Res r;
private int x = 0;
Input(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
synchronized (r)
{
if (r.flag)
try { r.wait(); }catch (InterruptedException e){}
if (x==0)
{
r.name = "mike";
r.sex = "man";
}
else
{
r.name = "麗麗";
r.sex = "女女女女女女";
}
x = (x+1)%2;
r.flag = true;
r.notify();
}
}
}
}
class Output implements Runnable
{
private Res r;
Output(Res r)
{
this.r = r;
}
public void run()
{
while (true)
{
synchronized (r)
{
if (!r.flag)
try { r.wait(); }catch (InterruptedException e){}
System.out.println(r.name+"....."+r.sex);
r.flag = false;
r.notify();
}
}
}
}
public class InputOutputDemo {
public static void main(String[] args) {
Res r = new Res();
Input in = new Input(r);
Output out = new Output(r);
Thread t1 = new Thread(in);
Thread t2 = new Thread(out);
t1.start();
t2.start();
}
}
//輸出
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
優化代碼為同步函數形式
class Res0 {
private String name;
private String sex;
private boolean flag = false;
public synchronized void set(String name, String sex) {
if (flag)
try { this.wait(); } catch (InterruptedException e) { }
this.name = name;
this.sex = sex;
flag = true;
this.notify();
}
public synchronized void out() {
if (!flag)
try { this.wait(); } catch (InterruptedException e) {}
System.out.println(name + "....." + sex);
flag = false;
this.notify();
}
}
class Input0 implements Runnable {
private Res0 r;
private int x = 0;
Input0(Res0 r) {
this.r = r;
}
public void run() {
while (true) {
if (x == 0) {
r.set("mike", "man");
} else {
r.set("麗麗", "女女女女女女");
}
x = (x + 1) % 2;
}
}
}
class Output0 implements Runnable {
private Res0 r;
Output0(Res0 r) {
this.r = r;
}
public void run() {
while (true) {
r.out();
}
}
}
public class InputOutputDemo0 {
public static void main(String[] args) {
Res0 r = new Res0();
new Thread(new Input0(r)).start();
new Thread(new Output0(r)).start();
}
}
//輸出
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
mike.....man
麗麗.....女女女女女女
多個生產者和消費者情況
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;
public synchronized void set(String name)
{
while(flag)
try { this.wait(); }catch (InterruptedException e){}
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+".....生產者"+this.name);
flag = true;
this.notifyAll();
}
public synchronized void out()
{
while(!flag)
try { this.wait(); }catch (InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"......消費者"+this.name);
flag = false;
this.notifyAll();
}
}
class Producer implements Runnable {
private Resource res;
Producer(Resource res)
{
this.res = res;
}
public void run()
{
while (true)
// for (int i = 0;i<1000;i++)
res.set("+商品+");
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res = res;
}
public void run()
{
while (true)
// for (int i = 0;i<1000;i++)
res.out();
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
Resource res = new Resource();
Producer p1 = new Producer(res);
Consumer c1 = new Consumer(res);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
為什么要定義while判斷標記。
原因:讓被喚醒的線程再一次判斷標記。
為什么定義nofigyAll,因為需要喚醒對方線程。因為只用notify,容易出現只喚醒本方線程的情況,導致程序中的所有線程都等待。
JDK1.5.0中提供了多線程升級解決方案。將同步Synchronized替換成顯示Lock操作。將Object中的wait,notify,notifyAll,替換了Condition對象。該對象可以Lock鎖進行獲取。該示例中,實現了本方只喚醒本方操作。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource0
{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try{
while(flag)
condition.await();
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+".....生產者"+this.name);
flag = true;
condition.signal();
}
finally {
lock.unlock();
}
}
public void out() throws InterruptedException
{
lock.lock();
try {
while(!flag)
condition.await();
System.out.println(Thread.currentThread().getName()+"......消費者"+this.name);
flag = false;
condition.signal();
}
finally {
lock.unlock();
}
}
}
class Producer0 implements Runnable {
private Resource0 res;
Producer0(Resource0 res)
{
this.res = res;
}
public void run()
{
while (true)
try{
// for (int i = 0;i<1000;i++)
res.set("+商品+");
}
catch (InterruptedException e)
{
}
}
}
class Consumer0 implements Runnable
{
private Resource0 res;
Consumer0(Resource0 res)
{
this.res = res;
}
public void run()
{
while (true)
try {
// for (int i = 0;i<1000;i++)
res.out();
}catch (InterruptedException e)
{
}
}
}
public class ProducerConsumerDemo0 {
public static void main(String[] args) {
Resource0 res = new Resource0();
Producer0 p1 = new Producer0(res);
Consumer0 c1 = new Consumer0(res);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//輸出:全部喚醒,程序無法結束
0.gif
condition.signal()喚醒本方線程,造成相互等待程序無法結束。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource0
{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try{
while(flag)
condition.await();
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+".....生產者"+this.name);
flag = true;
condition.signalAll();
}
finally {
lock.unlock();
}
}
public void out() throws InterruptedException
{
lock.lock();
try {
while(!flag)
condition.await();
System.out.println(Thread.currentThread().getName()+"......消費者"+this.name);
flag = false;
condition.signalAll();
}
finally {
lock.unlock();
}
}
}
class Producer0 implements Runnable {
private Resource0 res;
Producer0(Resource0 res)
{
this.res = res;
}
public void run()
{
while (true)
try{
// for (int i = 0;i<1000;i++)
res.set("+商品+");
}
catch (InterruptedException e)
{
}
}
}
class Consumer0 implements Runnable
{
private Resource0 res;
Consumer0(Resource0 res)
{
this.res = res;
}
public void run()
{
while (true)
try {
// for (int i = 0;i<1000;i++)
res.out();
}catch (InterruptedException e)
{
}
}
}
public class ProducerConsumerDemo0 {
public static void main(String[] args) {
Resource0 res = new Resource0();
Producer0 p1 = new Producer0(res);
Consumer0 c1 = new Consumer0(res);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//輸出正常
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Resource0
{
private String name;
private int count = 1;
private boolean flag = false;
private Lock lock = new ReentrantLock();
private Condition condition_pro = lock.newCondition();
private Condition condition_con = lock.newCondition();
// private Condition condition = lock.newCondition();
public void set(String name)throws InterruptedException
{
lock.lock();
try{
while(flag)
condition_pro.await();
this.name = name+"--"+count++;
System.out.println(Thread.currentThread().getName()+"...生產者"+this.name);
flag = true;
condition_con.signal();
}
finally {
lock.unlock();
}
}
public void out() throws InterruptedException
{
lock.lock();
try {
while(!flag)
condition_con.await();
System.out.println(Thread.currentThread().getName()+"..消費者"+this.name);
flag = false;
condition_pro.signal();
}
finally {
lock.unlock();
}
}
}
class Producer0 implements Runnable {
private Resource0 res;
Producer0(Resource0 res)
{
this.res = res;
}
public void run()
{
while (true)
try{
// for (int i = 0;i<1000;i++)
res.set("+商品+");
}
catch (InterruptedException e)
{
}
}
}
class Consumer0 implements Runnable
{
private Resource0 res;
Consumer0(Resource0 res)
{
this.res = res;
}
public void run()
{
while (true)
try {
// for (int i = 0;i<1000;i++)
res.out();
}catch (InterruptedException e)
{
}
}
}
public class ProducerConsumerDemo0 {
public static void main(String[] args) {
Resource0 res = new Resource0();
Producer0 p1 = new Producer0(res);
Consumer0 c1 = new Consumer0(res);
Thread t1 = new Thread(p1);
Thread t2 = new Thread(p1);
Thread t3 = new Thread(c1);
Thread t4 = new Thread(c1);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
//輸出正常
停止線程
stop方法已經過時。
如何停止線程?
只有一種,run方法結束。開啟多線程運行,運行代碼通常是循環結構。只要控制住循環,就可以讓run方法結束,也就是線程結束。
特殊情況:當線程處于了凍結狀態。
就不會讀取到標記,那么線程就不會結束。
當沒有指定的方式讓凍結的線程恢復到運行狀態時,這時需要對凍結狀態進行清除。
強制讓線程恢復到運行狀態中來。這樣就可以操作標記讓線程結束。
Thread類提供了該方法interrupt();
class StopThread implements Runnable
{
private Boolean flag = true;
public void run()
{
while (flag)
{
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo {
public static void main(String[] args) {
StopThread st = new StopThread();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while (true)
{
if (num++ == 60)
{
st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
}
}
//輸出正常:num到60,改變標記flag,結束循環,結束打印,結束線程。
...
main......50
Thread-0...run
main......51
Thread-1...run
main......52
Thread-0...run
main......53
Thread-1...run
main......54
Thread-0...run
main......55
Thread-1...run
main......56
main......57
main......58
Thread-0...run
Thread-0...run
main......59
Thread-1...run
main......60
Thread-0...run
Thread-1...run
線程無法中斷
class StopThread0 implements Runnable
{
private Boolean flag = true;
public synchronized void run()
{
while (flag)
{
try{
wait();
}catch (InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+"...run"+e.toString());
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo0 {
public static void main(String[] args) {
StopThread0 st = new StopThread0();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while (true)
{
if (num++ == 60)
{
st.changeFlag();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
System.out.println(Thread.currentThread().getName()+"over");
}
}
//輸出:程序無法結束
2.gif
class StopThread0 implements Runnable
{
private Boolean flag = true;
public synchronized void run()
{
while (flag)
{
try{
wait();
}catch (InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+"...run"+e.toString());
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo0 {
public static void main(String[] args) {
StopThread0 st = new StopThread0();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while (true)
{
if (num++ == 60)
{
// st.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
System.out.println(Thread.currentThread().getName()+"over");
}
}
//輸出:程序無法結束
4.gif
程序結束
class StopThread0 implements Runnable
{
private Boolean flag = true;
public synchronized void run()
{
while (flag)
{
try{
wait();
}catch (InterruptedException e)
{
System.out.println(Thread.currentThread().getName()+"...run"+e.toString());
flag = false;
}
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo0 {
public static void main(String[] args) {
StopThread0 st = new StopThread0();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.start();
t2.start();
int num = 0;
while (true)
{
if (num++ == 60)
{
// st.changeFlag();
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
System.out.println(Thread.currentThread().getName()+"over");
}
}
//輸出正常
main......50
main......51
main......52
main......53
main......54
main......55
main......56
main......57
main......58
main......59
main......60
mainover
Thread-0...runjava.lang.InterruptedException
Thread-0...run
Thread-1...runjava.lang.InterruptedException
Thread-1...run
守護線程
class StopThread1 implements Runnable
{
private Boolean flag = true;
public void run()
{
while (flag)
{
System.out.println(Thread.currentThread().getName()+"...run");
}
}
public void changeFlag()
{
flag = false;
}
}
public class StopThreadDemo1 {
public static void main(String[] args) {
StopThread1 st = new StopThread1();
Thread t1 = new Thread(st);
Thread t2 = new Thread(st);
t1.setDaemon(true);
t2.setDaemon(true);
t1.start();
t2.start();
int num = 0;
while (true)
{
if (num++ == 60)
{
// st.changeFlag();
// t1.interrupt();
// t2.interrupt();
break;
}
System.out.println(Thread.currentThread().getName()+"......"+num);
}
System.out.println(Thread.currentThread().getName()+"over");
}
}
//輸出
Thread-0...run
main......58
Thread-1...run
main......59
Thread-0...run
Thread-0...run
main......60
Thread-1...run
Thread-0...run
Thread-0...run
Thread-0...run
Thread-1...run
Thread-1...run
Thread-0...run
Thread-0...run
Thread-1...run
Thread-0...run
mainover
Thread-1...run
Thread-0...run
Thread-1...run
Thread-0...run
Thread-1...run
Thread-0...run
Thread-1...run
Thread-0...run
Thread-1...run
Thread-0...run
join方法:當A線程執行到了B線程的.join()方法時,A就會等待。等B線程都執行完,A才會執行。join可以用來臨時加入線程執行。
class Demo6 implements Runnable
{
public void run()
{
for (int x = 0;x<60;x++)
{
System.out.println(Thread.currentThread().getName()+"....."+x);
}
}
}
public class JoinDemo {
public static void main(String[] args) throws InterruptedException
{
Demo6 d = new Demo6();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t1.join();
t2.start();
for (int x=0;x<70;x++)
{
System.out.println("main......"+x);
}
System.out.println("over");
}
}
//輸出:t1線程執行完才回到主線程
...
Thread-0.....55
Thread-0.....56
Thread-0.....57
Thread-0.....58
Thread-0.....59
Thread-1.....0
Thread-1.....1
Thread-1.....2
...
優先級
class Demo7 implements Runnable
{
public void run()
{
for (int x = 0;x<60;x++)
{
System.out.println(Thread.currentThread().toString()+"....."+x);
}
}
}
public class PriorityYeildDemo {
public static void main(String[] args) throws InterruptedException
{
Demo7 d = new Demo7();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t1.setPriority(Thread.MAX_PRIORITY);
t2.start();
for (int x=0;x<70;x++)
{
System.out.println("main......"+x);
}
System.out.println("over");
}
}
//輸出:優先級為10
Thread[Thread-1,5,main].....0
Thread[Thread-0,10,main].....0
Thread[Thread-1,5,main].....1
Thread[Thread-0,10,main].....1
Thread[Thread-1,5,main].....2
Thread[Thread-0,10,main].....2
...
Thread[Thread-1,5,main].....57
Thread[Thread-0,10,main].....56
Thread[Thread-1,5,main].....58
Thread[Thread-0,10,main].....57
Thread[Thread-1,5,main].....59
Thread[Thread-0,10,main].....58
Thread[Thread-0,10,main].....59
yield
class Demo7 implements Runnable
{
public void run()
{
for (int x = 0;x<60;x++)
{
System.out.println(Thread.currentThread().toString()+"....."+x);
Thread.yield();
}
}
}
public class PriorityYeildDemo {
public static void main(String[] args) throws InterruptedException
{
Demo7 d = new Demo7();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
for (int x=0;x<70;x++)
{
System.out.println("main......"+x);
}
System.out.println("over");
}
}
//輸出:中斷當前線程,線程交替更頻繁
Thread[Thread-0,5,main].....0
Thread[Thread-0,5,main].....1
Thread[Thread-0,5,main].....2
Thread[Thread-1,5,main].....0
Thread[Thread-0,5,main].....3
Thread[Thread-1,5,main].....1
Thread[Thread-0,5,main].....4
Thread[Thread-1,5,main].....2
Thread[Thread-0,5,main].....5
Thread[Thread-1,5,main].....3
Thread[Thread-0,5,main].....6
多線程的使用:匿名內部類,繼承或實現封裝
public class ThreadTest {
public static void main(String[] args) {
new Thread(){
public void run()
{
for (int x = 0;x <100;x++)
{
System.out.println(Thread.currentThread().toString()+"..."+x);
}
}
}.start();
for (int x = 0;x <100;x++)
{
System.out.println(Thread.currentThread().toString()+"..."+x);
}
Runnable r = new Runnable(){
public void run()
{
for (int x = 0;x <100;x++)
{
System.out.println(Thread.currentThread().toString()+"..."+x);
}
}
};
new Thread(r).start();
}
}
//封裝
class Demo8 extends Thread
{
public void run()
{
for (int x = 0;x <100;x++)
{
System.out.println(Thread.currentThread().toString()+"..."+x);
}
}
}