Java多线程学习

多线程

(看传值博客视频记录下来点点滴滴传值博客)


多线程安全问题产生的前提

  1. 多个线程操作同一个共享变量
  2. 操作共享变量的代码超过2行

解决多线程安全问题方法

  1. 用同步代码块
  2. 同步函数
    注意必须保证线程用的是同一个锁这里锁可以是任何对象
    同步函数块的锁是this
    静态同步函数的锁是该类的字节码对象

死锁的产生

如果有run方法中有两个不同的锁A、B,一个线程先获得A锁,然后在请求B锁,现在另外一个线程同时获得了B锁,在请求A锁,那么就会发生死锁

代码部分后续会补上

多线程通讯

1、引入等待唤醒机制

package com.hfview.thread;
/**
 * 引出多线程通讯的问题
 * 目标:生成一个名字,然后输出一个名字
 * 不加入同步会出现名字和性别对应不上
 * 不加入等待唤醒机制 生成的名字不会立马输出,而是连续的一片
 * @author zhw
 */

/*共享资源*/
class Factory{
    public String name;
    public String sex;
}

/* 给factory赋值任务*/
class Input implements Runnable{
    Factory f;
    public Input(Factory factory){
        this.f=factory;
    }

    public void run() {
        int num=0;
        while(true){
            synchronized (Factory.class) {
                if(num==0){
                    f.name="zhanghongwei";
                    f.sex="男男男男男";
                }else{
                    f.name="hwj";
                    f.sex="女";
                }
            }
            num=(num+1)%2;
        }
    }

}

/* 给factory输出任务*/
class Output implements Runnable{
    Factory f;
    public Output(Factory factory){
        this.f=factory;
    }
    public void run() {
        while (true) {
            synchronized (Factory.class) {
                System.out.println("name:" + f.name + "   sex:" + f.sex);
            }
        }
    }
}

/*主函数*/
public class ThreadMsg1 {
    public static void main(String[] args) {
        Factory factory =new Factory();
        Input in=new Input(factory);
        Output out =new Output(factory);

        Thread t1=new Thread(in);
        Thread t2=new Thread(out);

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

2、利用等待唤醒机制解决问题

package com.hfview.thread;
/*
等待/唤醒机制。 

涉及的方法:

1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。
2,notify():唤醒线程池中一个线程(任意).
3,notifyAll():唤醒线程池中的所有线程。

这些方法都必须定义在同步中。
因为这些方法是用于操作线程状态的方法。
必须要明确到底操作的是哪个锁上的线程。


为什么操作线程的方法wait notify notifyAll定义在了Object类中? 

因为这些方法是监视器的方法。监视器其实就是锁。
锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。


针对ThreadMsg1的补充 这里就时加入了等待唤醒机制,可以完成生成一个名字输出一个名字的效果
还有一个问题就是这里是一个生产者一个消费者类型
*/

/*共享资源*/
class Factory2{
    public String name;
    public String sex;
    boolean flag=false;//false代表可以输出  true代表可以输出
}

/* 给factory赋值任务*/
class Input2 implements Runnable{
    Factory2 f;
    public Input2(Factory2 factory){
        this.f=factory;
    }

    public void run() {
        int num=0;
        while(true){
            synchronized (f) {
                if (f.flag==false) {
                    if (num == 0) {
                        f.name = "zhanghongwei";
                        f.sex = "男男男男男";
                    } else {
                        f.name = "hwj";
                        f.sex = "女";
                    }
                    num = (num + 1) % 2;
                    f.flag=true;
                    f.notify();
                }else{
                    try {
                        f.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

/* 给factory输出任务*/
class Output2 implements Runnable{
    Factory2 f;
    public Output2(Factory2 factory){
        this.f=factory;
    }
    public void run() {
        while (true) {
            synchronized (f) {
                if (f.flag) {
                    System.out.println("name:" + f.name + "   sex:" + f.sex);
                    f.flag=false;
                    f.notify();
                }else{
                    try {
                        f.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

/*主函数*/
public class ThreadMsg2 {
    public static void main(String[] args) {
        Factory2 factory =new Factory2();
        Input2 in=new Input2(factory);
        Output2 out =new Output2(factory);

        Thread t1=new Thread(in);
        Thread t2=new Thread(out);

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

3、引入多生产者多消费者问题

package com.hfview.thread;

/*
 等待/唤醒机制。 
针对多个生产者,多个消费者的解决
多生产者,多消费者的问题。
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!

notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。
notifyAll解决了本方线程一定会唤醒对方线程的问题。
 */

/*共享资源*/
class Factory3 {
    private String name;
    private int count = 1;
    boolean flag = false;// false代表可以生产 true代表可以销售

    /*
     * 注意这种使用notify会造成死锁的原因 这也是notifyAll的应用
     */
    public synchronized void make(String str) {
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            name = str + count;
            count++;
            System.out.println(Thread.currentThread().getName() + ":制造了手机"
                    + name);
            flag = true;
            this.notify();
        }
    }
    /*
     *如果 这种写法,那么一旦线程唤醒就会接着执行下面的语句
     *而不是在从新判断flag的值,这样的写法一定切记不可写
     *
     */
    public synchronized void make2(String str) {
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        name = str + count;
        count++;
        System.out.println(Thread.currentThread().getName() + ":制造了手机" + name);
        flag = true;
        this.notify();
    }

    public synchronized void show() {
        if (flag) {
            System.out.println(Thread.currentThread().getName() + ":销售了手机...."
                    + name);
            flag = false;
            this.notify();
        } else {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void show2() {
        if (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println(Thread.currentThread().getName() + ":销售了手机...."
                + name);
        flag = false;
        this.notify();
    }
}

/* 给factory赋值任务 */
class Input3 implements Runnable {
    Factory3 f;

    public Input3(Factory3 factory) {
        this.f = factory;
    }

    public void run() {
        while (true) {
            f.make("inphone");
        }
    }

}

/* 给factory输出任务 */
class Output3 implements Runnable {
    Factory3 f;

    public Output3(Factory3 factory) {
        this.f = factory;
    }

    public void run() {
        while (true) {
            f.show();
        }
    }
}

/* 主函数 */
public class ThreadMsg3 {
    public static void main(String[] args) {
        Factory3 factory = new Factory3();

        Input3 in = new Input3(factory);

        Output3 out = new Output3(factory);

        Thread t1 = new Thread(in);
        Thread t2 = new Thread(in);
        Thread t3 = new Thread(out);
        Thread t4 = new Thread(out);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
问题的出现:notifyAll()会唤醒这个锁上的所有线程,所以生产者线程不仅会唤醒消费者,也可能唤醒生成者线程,这就会浪费资源

4、1.5版本新特性解决上例不高效的问题

package com.hfview.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 利用jdk1.5新特性解决线程安全和通讯问题 
 * 这个例子是ThreadMsg3的另外一种写法,只不过更高效了
 * @author zhw
 *
 */

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

    final Lock lock =new ReentrantLock();
    final Condition makeCon = lock.newCondition();//生产者线程锁里面的封装监视器的方法的对象
    final Condition sellCon = lock.newCondition(); //消费者线程锁里面的封装监视器的方法的对象 

    public void make(String str){
        try {
            lock.lock(); //相当于syncsynchronized,这里就相当于获得一个锁
            while(flag){
                makeCon.await();//让当前的生产者线程阻塞
            }

            name=str+count;
            System.out.println("生成了....."+name);
            flag=true;
            count++;
            sellCon.signal();//让其他的一个消费者线程唤醒
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();//这里就是释放这个锁
        }
    }

    public void sell(){
        try {
            lock.lock();
            while(!flag){
                sellCon.await();//让当前的消费者线程阻塞
            }

            System.out.println("销售了"+name);
            flag=false;
            makeCon.signal();//让其他的一个生产者线程唤醒

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}

/* 给factory赋值任务 */
class Input4 implements Runnable {
    Factory4 f;

    public Input4(Factory4 factory) {
        this.f = factory;
    }

    public void run() {
        while (true) {
            f.make("inphone");
        }
    }

}

/* 给factory输出任务 */
class Output4 implements Runnable {
    Factory4 f;

    public Output4(Factory4 factory) {
        this.f = factory;
    }

    public void run() {
        while (true) {
            f.sell();
        }
    }
}

public class ThreadMsg4 {

    public static void main(String[] args) {
        Factory4 factory = new Factory4();

        Input4 in = new Input4(factory);

        Output4 out = new Output4(factory);

        Thread t1 = new Thread(in);
        Thread t2 = new Thread(in);
        Thread t3 = new Thread(out);
        Thread t4 = new Thread(out);

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

当生产者线程满足条件进入到等待make.await()后,这个生产者线程就会相当于绑定到makeCon这个Conditon上,最后所有的生产者线程都会绑定到makeCon上面。同理所有的消费者线程就会绑定到sellCon这个Conditon上,当调用makeCon.signal()后就只会唤醒生成者线程,当调用sellCon.signal()后就只会唤醒消费者线程,这样就会高效了。

5、多生产者多消费者实例问题
前面几种都是生成一个东西,然后立马输出,这样根本不符合现实情况

package com.hfview.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 利用jdk1.5新特性解决线程安全和通讯问题 
 * 这个例子是针对ThreadMsg4的改进,前面几种都是生成一个 马上销售一个
 * 但是现实中肯定不是这样的,这次是一次能生产10个
 * @author zhw
 *
 */

class Factory5{
    /*加入一个手机厂商工厂只能生产10个手机*/
    private String[] objArr = new String[10];

    /*记录生产手机的编号*/
    private int count=0;

    /*库存量*/
    private int num=0;

    final Lock lock =new ReentrantLock();
    final Condition makeCon = lock.newCondition(); 
    final Condition sellCon = lock.newCondition(); 

    public void make(String str){
        try {
            lock.lock();
            //加入库存已满
            while(num==objArr.length){
                makeCon.await(); 
            }

            //库存不满
            count++;
            objArr[num]=str+count;
            System.out.println(Thread.currentThread().getName()+"生产了...."+objArr[num]+"    当前数量:"+(num+1));
            num++;
            sellCon.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally{
            lock.unlock();
        }
    }

    public void sell(){
        try {
            lock.lock();
            while(num==0){
                sellCon.await();
            }
            System.out.println(Thread.currentThread().getName()+"销售了"+objArr[(num-1)]+"    当前数量:"+(num-1));
            num--;
            makeCon.signal();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
    }
}

/* 给factory赋值任务 */
class Input5 implements Runnable {
    Factory5 f;

    public Input5(Factory5 factory) {
        this.f = factory;
    }

    public void run() {
        while (true) {
            f.make("inphone");
        }
    }

}

/* 给factory输出任务 */
class Output5 implements Runnable {
    Factory5 f;

    public Output5(Factory5 factory) {
        this.f = factory;
    }

    public void run() {
        while (true) {
            f.sell();
        }
    }
}

public class ThreadMsg5 {

    public static void main(String[] args) {
        Factory5 factory = new Factory5();

        Input5 in = new Input5(factory);

        Output5 out = new Output5(factory);

        Thread t1 = new Thread(in);
        Thread t2 = new Thread(in);
        Thread t3 = new Thread(out);
        Thread t4 = new Thread(out);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值