Java 多線程 線程間通信-等待喚醒機制

線程間通訊:其實就是多個線程在操作同一個資源,但是操作的動作不同。

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);
        }
    }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 2,986評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,492評論 1 15
  • 三、多線程: 1、進程和線程: 進程:正在進行的程序。每一個進程執行都有一個執行順序,該順序是一個執行路徑,或者叫...
    佘大將軍閱讀 301評論 0 0
  • 林炳文Evankaka原創作品。轉載自http://blog.csdn.net/evankaka 本文主要講了ja...
    ccq_inori閱讀 668評論 0 4
  • 多線程 1、進程和線程 進程:正在進行的成序。每一個進程執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制...
    有_味閱讀 304評論 1 1