Java -- 多线程、并发、非同步

并发:同一个对象多个线程同时操作

线程同步:由于同一进程的多个线程共享同一个存储空间,在带来方便的同时,也带来了访问冲突的问题。为了保证数据在方法中被访问时加入锁机制(synchronized),当一个线程活得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可。

同步方法

public synchronized void method(int args) {}

synchronized方法控制对“成员变量|类变量”对象的访问,每个对象对应一把锁,每个synchronized方法都必须活得调用该方法的对象的锁才能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得锁,重新进入可执行状态。

同步块

同步容器

// 同步容器在内部已经实现同步块,只需要像正常容器创建与使用即可
import java.util.concurrent.CopyOnWriteArrayList;

public class SynContainer{
    public static void main(String[] args) throws InterruptedException{
        // 创建同步容器
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();

        for(int i=0; i<1000; i++){
            new Thread(()->{
                list.add(Thread.currentThread().getName();
            }).start();
        }
        Thread.sleep(100);
        System.out.println(list.size());
    }
}

死锁

过多的同步可能造成相互不释放资源,从而互相等待,一般发生于同步中持有多个对象的锁(锁套锁),因此在编写程序的时候,尽量不要锁套锁,不要再同一个代码块中同时持有多个对象锁。

// 容易发生死锁
public class DeadLock {
    public static void main(String[] args) {
        new UseResource().start();
        new UseResource().start();
    }
}
class Resource_1{}

class Resource_2{}

//该对象会使用资源
class UseResource extend Thread{
    private static final Resource_1 res1 = new Resource_1();    //创建资源对象
    private static final Resource_2 res2 = new Resource_2();        
    
    @Override 
    public void run(){
        UseWithDeadLock();
    }
    private void UseWithDeadLock(){    // 容易发生死锁
        // 锁套锁结构,容易发生死锁。
        synchronized(res1){
            // 做其他事情
            synchronized(res2){
            // 做其他事情
            }
        }   
    }
    private void UseWithoutDeadLock(){    // 解决死锁方法
        synchronized(res1){//做其他事情}
        synchronized(res2){//做其他事情}
    }
}

并发线程协作(Cooperation)-- 生产者消费者模式

生产者消费者模式需要解决的是线程之间的通信问题,其中有两种方法(管程法、红绿灯法)

管程法:

 

生产者:负责生产数据的模块(模块可能是方法、对象、线程、进程)

消费者:负责处理数据的模块

缓冲区:通过缓冲区消费者不能直接使用生产者的数据,只能是生产者将生产好的数据放入该区,消费者从缓冲区取数据。

package cooperation;

/**
 * 协作模型:生产者消费者实现方式:管程法
 *
 * @author Wuhua
 */
public class CoTest01 {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Producer(container).start();
        new Consumer(container).start();
    }
}

// 生产者
class Producer extends Thread {
    private SynContainer container;

    Producer(SynContainer container) {
        this.container = container;
    }


    @Override
    public void run() {
        // 生产
        for (int i = 0; i < 100; i++) {
            System.out.println("生产-->" + i + "个数据");
            container.push(new ProductData(i));
        }
    }
}

// 消费者
class Consumer extends Thread {

    private SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        // 消费
        for (int i = 0; i < 100; i++) {
            System.out.println("消费-->" + container.pop().id + "个数据");
        }
    }
}

// 缓冲区
class SynContainer {
    // 存储容器
    ProductData[] datas = new ProductData[10];
    private int count = 0;

    // 存储 生产
    synchronized void push(ProductData data) {
        // 何时能够生产?
        // 容器存在空间,即可生产,否则进入等待状态
        if (count == datas.length) {
            try {
                this.wait();    // 等待消费者通知阻塞解除
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.datas[count] = data;
        this.count++;
        this.notifyAll();   // 生产了数据,唤醒消费者消费数据
    }

    // 消费 获取
    synchronized ProductData pop() {
        // 何时消费?
        // 容器中是否存在数据
        // 没有数据,只能等待
        if (count == 0) {
            try {
                this.wait();    // 线程阻塞,等待生产者通知
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 存在数据则消费
        this.count--;
        ProductData data = this.datas[count];
        this.notifyAll();   // 存在空间,唤醒对方生产
        return data;
    }

}

// 数据
class ProductData {
    int id;

    ProductData(int id) {
        this.id = id;
    }
}

红绿灯法:

package cooperation;

/**
 * 协作模型:生产者消费者实现方式:信号灯法
 *
 * @author Wuhua
 */
public class CoTest02 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Actor(tv).start();
        new Audience(tv).start();

    }
}

// 消费者 观众
class Audience extends Thread {
    private TV tv;

    public Audience(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            tv.watch();
        }
    }
}


// 生产者 演员
class Actor extends Thread {
    private TV tv;

    public Actor(TV tv) {
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i % 2 == 0) {
                this.tv.play("奇葩说");
            } else {
                this.tv.play("广告");
            }
        }

    }
}

// 资源 电视
class TV {
    private String voice;
    // 信号灯
    // T 表示演员表演,观众等待
    // F 表示观众观看,演员等待
    private boolean flag = true;

    // 表演的时候观众等待
    synchronized void play(String voice) {
        // 演员等待
        if (!this.flag) {
            try {
                this.watch();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 表演
        System.out.println("表演了:" + voice);
        this.voice = voice;
        // 唤醒
        this.notifyAll();
        this.flag = !this.flag;
    }

    // 观看的时候演员等待
    synchronized void watch() {
        // 观众等待
        if (this.flag) {
            try {
                this.wait();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 观看
        System.out.println("听到了:" + this.voice);
        // 唤醒
        this.notifyAll();
        // 切换标志
        this.flag = !this.flag;
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值