Java教程

Java基础第二遍-12-多线程-同步-通信

本文主要是介绍Java基础第二遍-12-多线程-同步-通信,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

多线程安全问题原因

  1. 多个线程操作共享的数据
  2. 操作共享数据的线程有多个
  3. 其中一个线程操作共享数据的过程中,其他的线程参与了运算,就会产生线程安全问题

解决线程安全问题

  1. 锁机制
  2. 思路:将共享数据部分封装起来,当有线程进行操作的时候其他的线程不能参与运算,其中的线程执行完毕之后,其他的才可以参与运算
  3. 同步代码块可以解决这个问题:synchronized

同步的好处与弊端

  1. 好处:解决线程安全问题
  2. 弊端:将低了执行效率,同步外的线程都会判断同步锁

同步函数与同步代码块使用的锁

  1. 同步函数使用的锁是this,固定的
  2. 同步代码块可以使用任意的锁
  3. 所谓锁,就是一个对象

静态的同步函数使用的锁

  1. 使用的锁是该函数所属字节码文件对象,也就是Class对象,可以使用Object中的getClass方法获取,也可以用(当前类名.class)表示

创建线程的方式

  1. 继承Thread
  2. 实现Runnbale
    1. 将线程任务从线程的子类中分离出来,进行了单独的封装
    2. 避免了Java单继承的局限性
    3. 较为常用
  3. callable
  4. 线程池

多线程下的单例模式

  1. 饿汉式
    1. 类一加载就创建对象
  2. 懒汉式
    1. 要使用的时候才创建对象
  3. 多线程下使用单例模式使用饿汉式,实现起来较为简单
  4. 懒汉式需要解决,线程不安全问题和效率问题
    使用同步解决线程安全问题,使用if判断解决效率问题
//懒汉式
class Single{
    private static Single s = null;
    private Single(){}
    public static Single getInstance(){
        if(s==null){
            synchronized (Single.class){
                if (s==null){
                    return new Single();
                }
            }
        }
        return s;
    }
}

生产者消费者模式

synchronized模式实现:在多消费者多生产者模式的情况下,只能使用notifyAll()的方式,使用notify()的方式有可能死锁。

package com.bixiangdong.thread;

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+count);
        flag=true;
        notifyAll();//这里使用notifyAll是因为如果 生产者有多个的话,notify唤醒的可能总是生产者的线程,然后因为flag=flase就总是等待,可能会发生死锁的情况
    }
    public synchronized void get(){
        while (!flag){
            try {
                this.wait();
            }catch (InterruptedException e){

            }
        }
        System.out.println(Thread.currentThread().getName()+"----消费者----"+this.name+count);
        flag=false;
        notifyAll();
    }
}
class Productor implements Runnable{
    private Resource r;
    public Productor(Resource r){
        this.r=r;
    }

    @Override
    public void run() {
        while (true){
            r.set("牛奶");
        }
    }
}
class Customer implements Runnable{
    private Resource r;
    public Customer(Resource r){
        this.r=r;
    }

    @Override
    public void run() {
        while (true){
            r.get();
        }
    }
}
public class Demo03 {
    public static void main(String[] args) {
        Resource resource = new Resource();
        Productor productor = new Productor(resource);
        Customer customer = new Customer(resource);
        new Thread(productor).start();
        new Thread(customer).start();
    }
}

lock实现方式:JDK1.5支持了lock方式,可以实现一个lock有多个condition,可以实现生产者通知消费者,更加精准,生产者只用唤醒一个消费者就行,消费者也是如此

package com.bixiangdong.thread;


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

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

    //创建锁
    Lock lock = new ReentrantLock();
    //通过已有的锁创建两组监视器
    Condition pro_con = lock.newCondition();
    Condition cus_con = lock.newCondition();

    public void set(String name){
        //设置锁
        lock.lock();
        while (flag){
            try {
                pro_con.await();
            }catch (InterruptedException e){

            }
        }
        this.name=name;
        count++;
        System.out.println(Thread.currentThread().getName()+"----生产者----"+this.name+count);
        flag=true;
        //notifyAll();//这里使用notifyAll是因为如果 生产者有多个的话,notify唤醒的可能总是生产者的线程,然后因为flag=flase就总是等待,可能会发生死锁的情况
        cus_con.signal();//只需要唤醒一个消费者就ok
        //释放锁
        lock.unlock();
    }
    public void get(){
        lock.lock();
        while (!flag){
            try {
                cus_con.await();
            }catch (InterruptedException e){

            }
        }
        System.out.println(Thread.currentThread().getName()+"----消费者----"+this.name+count);
        flag=false;
        //notifyAll();
        pro_con.signal();
        lock.unlock();
    }
}
class Productor2 implements Runnable{
    private Resource2 r;
    public Productor2(Resource2 r){
        this.r=r;
    }

    @Override
    public void run() {
        while (true){
            r.set("牛奶");
        }
    }
}
class Customer2 implements Runnable{
    private Resource2 r;
    public Customer2(Resource2 r){
        this.r=r;
    }

    @Override
    public void run() {
        while (true){
            r.get();
        }
    }
}
public class Demo04 {
    public static void main(String[] args) {
        Resource2 resource = new Resource2();
        Productor2 productor = new Productor2(resource);
        Customer2 customer = new Customer2(resource);
        new Thread(productor).start();
        new Thread(productor).start();
        new Thread(productor).start();
        new Thread(customer).start();
        new Thread(customer).start();
        new Thread(customer).start();
    }
}

wait和sleep的区别

  1. wait可以指定时间,也可以不指定
  2. sleep必须指定时间
    在同步时,对cpu的执行权和锁的处理不同
  3. wait:释放执行权,释放锁
  4. sleep:释放执行权,不释放锁

线程的结束

  1. 线程中run方法结束,则线程结束
  2. 如何结束run方法,通过改变标志
    标记法
package com.bixiangdong.thread;
class A1 implements Runnable{
    public boolean flag = true;
    @Override
    public void run() {
        while (flag){
            System.out.println("一直运行"+Thread.currentThread().getName());
        }
    }
}

public class Demo05 {
    public static void main(String[] args) {
        A1 a1 = new A1();
        new Thread(a1).start();
        new Thread(a1).start();
        int num=0;
        for (;;){
            num++;
            if (num==100000){
                a1.flag=false;
                break;
               // System.exit(0);
            }
            System.out.println("-----------");
        }
    }
}
这篇关于Java基础第二遍-12-多线程-同步-通信的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!