Java 学习笔记——线程间通信(day12)

内容概要:
1. 线程间通信的示例代码
2. 安全问题的解决
3. 等待唤醒机制
4. 代码优化
5. 生产者消费者例子
6. 生产者消费者例子代码优化(JDK5.0升级版)

  • 1.线程间通信

    线程间通信,其实就是多个线程在操作同一个资源,但是操作的动作不同。

class Res
{
    String name;
    String sex;
}
class Input implements Runnable
{
    int x = 0;
    private Res r;
    public Input(Res r)
    {
        this.r = r;
    }
    public void run()
    {
        while (true)
        {
            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)
        {
            System.out.println(r.name+"++++++"+r.sex);
        }
    }
}

class InputOutputDemo
{
    public static void main(String[] args)
    {
        Res r = new Res();

        Input i = new Input(r);
        Output o = new Output(r);

        Thread t1 = new Thread(i);
        Thread t2 = new Thread(o);

        t1.start();
        t2.start();
    }
}

运行出现了错误的输出
可以发现,运行输出出现了错误的情况。

  • 2.安全问题的解决

    在上边的示例代码运行后,发现有输出错误这样的安全问题,这里需要去解决。
    通过分析发现,这种错误的产生来源是,多线程运行的时候,交叉取得CPU权限时中断的随机性导致。
    解决的思路:
    1). 考虑是否多线程
    2). 是否使用同一把锁

更改后代码

class Res
{
    String name;
    String sex;
}

class Input implements Runnable
{
    private Res r;

    Input(Res r)
    {
        this.r = r;
    }
    public void run()
    {
        int x = 0;
        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);
            }
        }
    }
}

class InputOutputDemo 
{
    public static void main(String[] args) 
    {
        Res r = new Res();

        Input i = new Input(r);
        Output o = new Output(r);

        Thread t1 = new Thread(i);
        Thread t2 = new Thread(o);

        t1.start();
        t2.start();
    }
}

更改代码后输出无错误
运行发现,修改后的代码输出无错误,但是出现了大片连续的相同输出。

  • 3.等待唤醒机制
    鉴于前述解决了安全问题后,多线程运行不够理想——非交替运行状态。
    那么要实现交替运行该如何办呢?
    这里要用到wait和notify方法。

    wait()
    notify()
    notifyAll()
    以上几个方法,都是用在同步中的,我们要对持有监视器(锁)的线程操作,便要用到以上的方法。
    
    只有同步才具有锁。
    为什么这些操作线程的方法要定义Object类中嗯?
    

    因为这些方法在操作同步中线程时,都必须要标示他们所操作线程只有的锁,
    只有同一个锁上的被等待的线程,可以被同一个锁上的notify唤醒。
    不可以对不同锁中的线程进行唤醒,

    也就是,等待和唤醒必须是同一个锁

    而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。

class Res
{
    String name;
    String sex;
    boolean flag = true;
}

class Input implements Runnable
{
    private Res r;

    Input(Res r)
    {
        this.r = r;
    }
    public void run()
    {
        int x = 0;
        while(true)
        {
            synchronized(r)//同步对象的选用
            {
                if (r.flag)
                    try{r.wait();} catch (Exception 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 (Exception e){}                
                System.out.println(r.name+"++++++"+r.sex);
                r.flag = false;
                r.notify();
            }
        }
    }
}

class waitnotifyDemo 
{
    public static void main(String[] args) 
    {
        Res r = new Res();

        Input i = new Input(r);
        Output o = new Output(r);

        Thread t1 = new Thread(i);
        Thread t2 = new Thread(o);

        t1.start();
        t2.start();
    }
}

交替运行

运行输出如图,代码加入等待唤醒机制后,实现了线程交替运行的目的。

  • 4.代码优化

    代码优化:
    方向:数据私有化,提供访问方法。

class Res
{
    private String name;        //应当私有化
    private String sex;
    private boolean flag = false;
    public synchronized void set(String name,String sex)//提供数据访问方法
    {
        if (flag)
            try{wait();} catch (Exception e){}
        this.name = name;
        this.sex = sex;
        flag = true;
        this.notify();
    }
    public synchronized void out()//提供数据访问方法
    {
        if (!flag)  
            try{wait();} catch (Exception e){}

            System.out.println(name+"++++++"+sex);

        flag = false;       
        this.notify();
    }
}

class Input implements Runnable
{
    private Res r;

    Input(Res r)
    {
        this.r = r;
    }
    public void run()
    {
        int x = 0;
        while(true)
        {
                if (x==0)
                    r.set("mike","man");
                else
                r.set("丽丽","女女女女女女");
                x= (x+1)%2;
        }
    }
}

class Output implements Runnable
{
    private Res r;
    Output(Res r)
    {
        this.r = r;
    }
    public void run()
    {
        while (true)
        {
            r.out();
        }
    }
}

class IODemo1 
{
    public static void main(String[] args) 
    {
        Res r = new Res();



        new Thread(new Input(r)).start();
        new Thread(new Output(r)).start();

        Input i = new Input(r);
        Output o = new Output(r);

        Thread t1 = new Thread(i);
        Thread t2 = new Thread(o);

        t1.start();
        t2.start();
    }
}
  • 5.生产者消费者例子

当有多个生产者,多个消费者时,必须循环判断标记,避免生产多个,消费一个,或者生产一个,消费多次等情况出现

class Resource
{
    private String name;
    private int count = 1;
    private boolean flag = false;

    public synchronized void set(String name)
    {
        while (flag)
        {
            try
            {
                wait();
            }
            catch (Exception e)
            {
            }
        }
        this.name = name+" "+count++;
        System.out.println(Thread.currentThread().getName()+"<++++++生产者+.."+this.name);
        flag = true;
        notifyAll();
    }

    public synchronized void get()
    {
        while (!flag)
        {
            try
            {
                wait();
            }
            catch (Exception e)
            {
            }
        }
        System.out.println(Thread.currentThread().getName()+"------>消费者-"+name);
        flag = false;
        notifyAll();
    }
}

class Producer implements Runnable
{
    private Resource r;
    public Producer(Resource r)
    {
        this.r = r;
    }
    public void run()
    {
        while (true)
        {
            r.set("product");
        }
    }
}

class Consumer implements Runnable
{
    private Resource r;
    public Consumer(Resource r)
    {
        this.r = r;
    }
    public void run()
    {
        while (true)
        {
        r.get();
        }
    }
}


class ProducerConsumerDemo 
{
    public static void main(String[] args) 
    {
        Resource r = new Resource();

        Producer p = new Producer(r);
        Consumer c = new Consumer(r);

        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

        t1.start();
        t2.start();
    }
}
  • 6.生产者消费者例子代码优化(JDK5.0升级版)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值