线程状态

线程状态 导致状态发生条件
NEW(新建) 线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行)
线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操
作系统处理器。
Blocked(锁阻塞)
当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状
态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待)
一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个
状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
TimedWaiting(计时等待)
同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态
将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、
Object.wait。Teminated(被终止)
因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

两个不同线程操作同一个资源
使用同步来完成,锁使用共享的资源对象,但会造成线程阻塞,同一时间段只会输出同一输入,无法做到输出当时输入的

线程间通信的方法
wait():调用了 wait()方法的线程进入等待池进行等待,等待
池中的线程不去竞争对象锁,直到其它的线程通知,才会进入
锁池
notify():随机唤醒一个在该对象上等待的线 程,被唤醒的线
程进行锁池,开始竞争该对锁上的锁
notifyAll():唤醒所有在该对象上等待的线程
优先级高的线程有可能先竞争到对象锁
只能在同步方法和同步代码块中使用

  1. //Resource
  2. public class Resource {
  3. String name;
  4. String sex;
  5. }
  6. //Input
  7. public class Input implements Runnable{
  8. Resource r;
  9. public Input(Resource r) {
  10. this.r = r;
  11. }
  12. @Override
  13. public void run() {
  14. int x=0;
  15. while(true){
  16. synchronized (r){
  17. if(x==0){
  18. r.name="yk";
  19. r.sex="male";
  20. }else{
  21. r.name="kk";
  22. r.sex="female";
  23. }
  24. }
  25. x=(x+1)%2;
  26. }
  27. }
  28. }
  29. //Output
  30. public class Output implements Runnable{
  31. Resource r;
  32. Output(Resource r){
  33. this.r = r;
  34. }
  35. @Override
  36. public void run() {
  37. while(true){
  38. synchronized (r){
  39. System.out.println(r.name+"...."+r.sex);
  40. }
  41. }
  42. }
  43. }
  44. //main
  45. Resource r = new Resource();
  46. Input in = new Input(r);
  47. Output ot = new Output(r);
  48. Thread tInput = new Thread(in);
  49. Thread tOutput = new Thread(ot);
  50. tInput.start();
  51. tOutput.start();

等待唤醒

  • wait():让线程处于冻结状态,释放CPU执行权和执行资格,会被存储到线程池中
  • notify():唤醒线程池中任意一个线程,具备执行资格
  • notifyAll():唤醒线程池中所有线程

这些方法必须在同步代码中,因为这些方法是用于操作线程状态的方法,必须要明确到底操作的是哪个锁上的线程
都是定义在Object中,所以要用锁对象来调用,作为监视器

调用wait和notify方法需要注意的细节

  1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
  2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
  3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。
//Resource
public class Resource {
    String name;
    String sex;
    boolean flag=false;
}
//Input
public class Input implements Runnable{
    Resource r;

    public Input(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        int x=0;
        while(true){
            synchronized (r){
                if(r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(x==0){
                    r.name="yk";
                    r.sex="male";
                }else{
                    r.name="kk";
                    r.sex="female";
                }
                r.flag=true;
                r.notify();
            }
            x=(x+1)%2;
        }
    }
}
//Output
public class Output implements Runnable{
    Resource r;
    Output(Resource r){
        this.r = r;
    }

    @Override
    public void run() {
        while(true){
            synchronized (r){
                if(!r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(r.name+"...."+r.sex);
                r.flag=false;
                r.notify();
            }
        }
    }
}
//main
Resource r = new Resource();
Input in = new Input(r);
Output ot = new Output(r);

Thread tInput = new Thread(in);
Thread tOutput = new Thread(ot);

tInput.start();
tOutput.start();

代码优化,输入,输出函数放入对象中

//Resource
public class Resource {
    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) {
                e.printStackTrace();
            }
        }
        this.name = name;
        this.sex = sex;
        flag=true;
        this.notify();
    }
    public synchronized void out(){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(name+"...."+sex);
        flag=false;
        this.notify();
    }


}
//Input
public class Input implements Runnable{
    Resource r;

    public Input(Resource r) {
        this.r = r;
    }

    @Override
    public void run() {
        int x=0;
        while(true){
            synchronized (r){
                if(x==0){
                    r.set("yk","male");
                }else{
                    r.set("kk","female");
                }
            }
            x=(x+1)%2;
        }
    }
}
//Output
public class Output implements Runnable{
    Resource r;
    Output(Resource r){
        this.r = r;
    }

    @Override
    public void run() {
        while(true){
            r.out();
        }
    }
}
//main
Resource r = new Resource();
Input in = new Input(r);
Output ot = new Output(r);

Thread tInput = new Thread(in);
Thread tOutput = new Thread(ot);

tInput.start();
tOutput.start();

线程通信 - 图1

生产者 消费者

1,持有锁
2,判断业务条件是否满足,若不满足则等待
3,唤醒在此监视器上的线程

多生产多消费

//RoastDuck
public class RoastDuck {
    private String name;
    private int count = 1;
    private boolean flag=false;

    public synchronized void produce(String name){
        while(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name + count;
        count++;
        System.out.println("producer..."+Thread.currentThread().getName()+"..."+this.name);
        flag=true;
        notifyAll();
    }
    public synchronized void consume(){
        while(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("consumer..."+Thread.currentThread().getName()+"..."+this.name);
        flag=false;
        notifyAll();
    }
}
//DuckProductor
public class DuckProductor implements Runnable {

    RoastDuck rd;

    public DuckProductor(RoastDuck rd) {
        this.rd = rd;
    }

    @Override
    public void run() {
        while (true){
            rd.produce("烤鸭");
        }
    }
}
//DuckConsumer
public class DuckConsumer implements Runnable {

    RoastDuck rd;

    public DuckConsumer(RoastDuck rd) {
        this.rd = rd;
    }

    @Override
    public void run() {
        while (true){
            rd.consume();
        }
    }
}
//main
RoastDuck rd = new RoastDuck();
DuckProductor dp = new DuckProductor(rd);
DuckConsumer dc = new DuckConsumer(rd);

Thread t0 = new Thread(dp);
Thread t1 = new Thread(dp);
Thread t2 = new Thread(dc);
Thread t3 = new Thread(dc);

t0.start();
t1.start();
t2.start();
t3.start();

重点在于 while notifyAll的理解

  • while 解决线程获取执行权后是否要运行,如果是if,醒来后不会判断flag,直接执行后面代码,所以有问题
  • notify只会唤醒一个线程,如果是本方,就容易出现等待死锁;notifyAll解决本方线程可以唤醒对方线程

JDK1.5-lock

将同步和锁封装成了对象,并将操作锁的隐式方法显示化

  • Lock:替代了同步代码块或函数;将同步锁的隐式操作变成显示操作,更为灵活,可以一个锁提供多个监视器,unlock需要定义在finally中
  • Condition:替代Object中的wait、notify等方法,可以任意锁组合 await singal singalAll
//RoastDuck
public class RoastDuck {
    private String name;
    private int count = 1;
    private boolean flag=false;
    Lock lock = new ReentrantLock();
    Condition pro_con = lock.newCondition();
    Condition com_con = lock.newCondition();

    public void produce(String name){
        lock.lock();
        try {
            while(flag){
                try {
                    pro_con.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.name = name + count;
            count++;
            System.out.println("producer5.0..."+Thread.currentThread().getName()+"..."+this.name);
            flag=true;
            com_con.signal();
        }finally {
            lock.unlock();
        }

    }
    public void consume(){
        lock.lock();
        try {
            while(!flag){
                try {
                    com_con.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("consumer5.0..."+Thread.currentThread().getName()+"..."+this.name);
            flag=false;
            pro_con.signal();
        }finally {
            lock.unlock();
        }

    }
}

锅盔

/**
 * @author yuankun
 * @date 2018.12.21
 * @Description 锅盔资源类-每次只提供一个锅盔
 */
public class GuoKui {

    private int counter = 0;
    private String name;
    private boolean flag = false;

    // 生产者
    public synchronized void Product(String name){

        // 如果有锅盔则等待消费
        if(flag){
            try {

                this.wait();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //生产锅盔
        counter++;
        this.name = name + counter;
        flag = true;
        System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name+" | 有锅盔了快来买!");
        notifyAll();

    }
    // 消费者
    public synchronized void consume(){

        // 没有锅盔就等待生产
        if(!flag){
            try {

                this.wait();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        flag = false;
        System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name+" | 锅盔被买走!");
        notifyAll();

    }
}

/**
 * @author yuankun
 * @date 2018.12.21
 * @Description 生产者线程类,调用Guokui资源
 */
public class Product implements Runnable {

    private GuoKui gk;
    private Thread t;

    public Product(GuoKui gk) {
        this.gk = gk;
        t = new Thread(this);
        t.start();
    }

    public void run() {

        for(int i=0;i<10;i++){
            gk.Product("袁琨牌大锅盔");
        }

    }
}

/**
 * @author yuankun
 * @date 2018.12.21
 * @Description 消费者线程类,调用Guokui资源
 */
public class Consumer implements Runnable {

    private GuoKui gk;
    private Thread t;

    public Consumer(GuoKui gk) {
        this.gk = gk;
        t = new Thread(this);
        t.start();
    }

    public void run() {

        for(int i=0;i<10;i++){

            gk.consume();

        }

    }
}

/**
 * @author yuankun
 * @date 2018.12.21
 * @Description 执行类
 */
public class Sell_Guokui {

    public static void main(String args[]){

        GuoKui gk = new GuoKui();

        new Product(gk);
        new Consumer(gk);
    }
}

生产者消费者2

/**
 * 共享对象Goods
 * @author Administrator
 *
 */
public class Goods {

    private String brand;
    private String name;
    private boolean isFlag;
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Goods(String brand, String name) {
        super();
        this.brand = brand;
        this.name = name;
    }
    public Goods() {
        super();
    }

    public synchronized void set(String brand, String name)  {
        if(isFlag) {
            try {
                wait();
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
        this.setBrand(brand);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
        this.setName(name);
        this.notifyAll();
        isFlag=true;
    }
    public synchronized void get()  {
        if(!isFlag) {
            try {
                wait();
            } catch (InterruptedException e) {

                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {

            e.printStackTrace();
        }
        System.out.println("消费者消费了"+this.getBrand()+this.getName());
        notifyAll();
        isFlag=false;
    }
}


/**
 * 生产者
 * @author Administrator
 *
 */
public class Produce implements Runnable {

    private Goods goods;

    public Produce(Goods goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        for(int i=0;i<10;i++) {
            if(i%2==0) {
                goods.set("北京", "烤鸭");
            }else {
                goods.set("成都", "兔头");
            }
            System.out.println("生产者生产了"+goods.getBrand()+goods.getName());
        }
    }
}

/**
 * 消费者
 * @author Administrator
 *
 */
public class Consume implements Runnable {

    private Goods goods;

    public Consume(Goods goods) {
        super();
        this.goods = goods;
    }

    @Override
    public void run() {
        for(int i=0;i<10;i++) {
            goods.get();
        }

    }
}

//测试类
public class Test {
    public static void main(String[] args) throws InterruptedException {

        Goods goods = new Goods();
        Produce produce = new Produce(goods);
        Consume consume = new Consume(goods);

        Thread tpThread = new Thread(produce);
        Thread tcThread = new Thread(consume);

        tpThread.start();
        Thread.sleep(100);
        tcThread.start();
    }
}

包子

01_等待与唤醒案例分析(1).jpg

包子资源类:

public class BaoZi {
     String  pier ;
     String  xianer ;
     boolean  flag = false ;//包子资源 是否存在  包子资源状态
}

吃货线程类:

public class ChiHuo extends Thread{
    private BaoZi bz;

    public ChiHuo(String name,BaoZi bz){
        super(name);
        this.bz = bz;
    }
    @Override
    public void run() {
        while(true){
            synchronized (bz){
                if(bz.flag == false){//没包子
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("吃货正在吃"+bz.pier+bz.xianer+"包子");
                bz.flag = false;
                bz.notify();
            }
        }
    }
}

包子铺线程类:

public class BaoZiPu extends Thread {

    private BaoZi bz;

    public BaoZiPu(String name,BaoZi bz){
        super(name);
        this.bz = bz;
    }

    @Override
    public void run() {
        int count = 0;
        //造包子
        while(true){
            //同步
            synchronized (bz){
                if(bz.flag == true){//包子资源  存在
                    try {

                        bz.wait();

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 没有包子  造包子
                System.out.println("包子铺开始做包子");
                if(count%2 == 0){
                    // 冰皮  五仁
                    bz.pier = "冰皮";
                    bz.xianer = "五仁";
                }else{
                    // 薄皮  牛肉大葱
                    bz.pier = "薄皮";
                    bz.xianer = "牛肉大葱";
                }
                count++;

                bz.flag=true;
                System.out.println("包子造好了:"+bz.pier+bz.xianer);
                System.out.println("吃货来吃吧");
                //唤醒等待线程 (吃货)
                bz.notify();
            }
        }
    }
}

测试类:

public class Demo {
    public static void main(String[] args) {
        //等待唤醒案例
        BaoZi bz = new BaoZi();

        ChiHuo ch = new ChiHuo("吃货",bz);
        BaoZiPu bzp = new BaoZiPu("包子铺",bz);

        ch.start();
        bzp.start();
    }
}