java学习笔记(?):多线程(中上)

太难了,学不会,晚上去码头整点儿薯条


一、线程控制

在上一篇笔记中,提到了生命周期。
线程控制就是生命周期状态之间的切换。

1.1常用方法(更多查询API

  • 休眠sleep方法
    static void sleep(long time) // 让当前线程暂停,不会释放锁。

time 是休眠时间,单位ms

  • 守护线程

守护线程是一种特殊的线程,当所有非守护线程结束后,即使守护线程没有运行完也会结束。
final void setDaemon(boolean on) //设置守护线程

  • 礼让线程yield方法

把执行权让出去,但是没完全让出去(自身仍然会去抢占线程。
public static void yield()

  • 插队线程join方法

当前线程暂停,等待插入线程结束后再继续。
public static void join()

1.2 等待唤醒机制

  • 线程等待void wait():会一直处于阻塞状态,直到被唤醒
  • 唤醒一个notify():随机唤醒当前对象下,一个等待的线程。
  • 唤醒一个notifyAll():唤醒当前对象下,所有等待的线程。

当前对象指的是监视器对象,锁对象带监视器对象。
我们知道锁会把别的线程拒之门外,如果已经有线程在运行的话。这时候等待进来的代码就会放在等待队列中,受这个锁对象的监视器对象监视。不同锁下的线程不能相互唤醒
插一句,同步方法中自动用的是this,也就是说,锁是该方法所在的实例

二、线程通信

上一篇笔记利用同步代码块保证了共享数据的安全性,但是有时候我们需要两个线程交替对数据进行访问。
并发:某一个时刻,处理处理这个,处理处理那个,同一时间点只执行一个任务。
并行:同一时间点,处理不同任务

2.1 利用等待唤醒机制实现交替运行

public class day01{
    static int flag = 1;
    public static void main(String[] args) {

        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (day01.class){
                        if(flag == 2){
                            try {
                                day01.class.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(getName() + ":" + i);
                        day01.class.notify();
                        flag = 2;
                    }
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (day01.class){
                        if(flag == 1){
                            try {
                                day01.class.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(getName() + ":" + i);
                        day01.class.notify();
                        flag = 1;
                    }
                }
            }
        }.start();

    }
}

2.2 生产者消费者模型

进一步扩展,我们可以把交替实现的两个线程看作生产者消费者
实际上有时候生产者生产的很快,而消费者很慢,反之亦有之。轮流会降低效率,因此这个模型增加了缓存区。
生产者消费者模型
加入缓存区的好处:

1.提高了效率:
例,生产者生产的时间为:1,5,1,5,1。
消费者消耗所需要的时间:5,1,5,1,5。
那么按照轮流执行所需要的总时间为:1+5+5+1+1+5+5+1+1+5=30
假设有一个长度为2的缓存区,那么需要的时间是:1+5+1+1+1+5=14
2.解耦了生产者和消费者
之前需要生产者和消费者相互通知,现在由缓冲区来进行通知,各司其职,易于维护。

public class SandX {
    //生产者和消费者,中间需要一个缓存区
    public static void main(String[] args) {
        DataBuffer dataBuffer = new DataBuffer(10);
        X x = new X(dataBuffer);
        S s = new S(dataBuffer);
        s.start();
        x.start();
    }
}
class Data<T>{
    private final T data;

    Data(T t){ this.data = t; }

    public T getData() { return data; }
}
class DataBuffer{
    private int index;
    final private int capacity;
    final private Object[] dataBuffer;
    DataBuffer(int capacity){
        this.capacity = capacity;
        dataBuffer = new Object[capacity];
    }

    //存数据
    public synchronized void push(Data data){
        if(index == capacity){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        dataBuffer[index] = data.getData();
        index++;
        notify();
    }
    //取数据
    public synchronized Object pop(){
        if(index == 0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        index--;
        notify();
        return dataBuffer[index];
    }
}

class S extends Thread{
    final private DataBuffer dataBuffer;

    public S(DataBuffer dataBuffer){
        this.dataBuffer = dataBuffer;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我正在生产数据:"+i);
            Data<Integer> data = new Data<>(i);
            dataBuffer.push(data);
        }
    }
}
class X extends Thread{
    final private DataBuffer dataBuffer;

    public X(DataBuffer dataBuffer){
        this.dataBuffer = dataBuffer;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("我正在消耗数据:"+dataBuffer.pop());
        }
    }
}

整薯条儿去喽

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值