线程基础核心 05 线程相关方法

admin / 开发 / ... / Reads: 3

1.案例:wait/notify/notifyAll

方法简述:

wait:释放线程拥有的当前锁对象,让线程进入WAITING状态

notify:唤醒当前锁对象等待池(WaitSet)中,某一个线程

notifyAll:唤醒当前锁对象等待池(WaitSet)中,所有线程

业务描述:

1.通过wait与notify(notifyAll)实现线程协同,实现经典的生产者消费者模式

2.编写生产者,向队列中生产数据,如果队列满,生产者进行等待,并唤醒消费者进行消费

3.编写消费者,从队列中消费数据,如果队列空,消费者进行等待,并唤醒生产者进行生产

4.在主类main方法中,创建两个生产者线程进行生产

5.在主类main方法中,创建一个消费者线程进行消费

生产者:

/**
 * 生产者
 */
class Producer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否满,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.size() ==
                        ProducerConsumerDemo.CAPACITY){
                    // 如果队列满,则等待消费者消费
                    try {
                        System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待消费者消费.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不满,则正常生产
                ProducerConsumerDemo.QUEUE.add(1);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒消费者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

消费者:

/**
 * 消费者
 */
class Consumer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否空,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.isEmpty()){
                    // 如果队列空,则等待生产者生产
                    try {
                        System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待生产者生产.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不空,则正常消费
                ProducerConsumerDemo.QUEUE.remove(0);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒生产者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

完整代码:

package com.anan.thread.threadmethod;

import java.util.ArrayList;

/**
 * 生产者消费者模型:wait与notify(notifyAll)
 */
public class ProducerConsumerDemo {

    // 定义公共资源:队列容量、队列
    public final static Integer CAPACITY = 6;
    public final static ArrayList<Integer> QUEUE = new ArrayList<Integer>(CAPACITY);

    // 定义锁对象
    public final static Object LOCK = new Object();

    public static void main(String[] args) {

        // 创建两个生产者线程
        Runnable r1 = new Producer();
        Thread producer0 = new Thread(r1,"producer-0");
        producer0.start();

        Thread producer1 = new Thread(r1,"producer-1");
        producer1.start();

        // 创建消费者线程
        Runnable r2 = new Consumer();
        Thread consumer1 = new Thread(r2,"consumer-0");
        consumer1.start();

    }
}

/**
 * 生产者
 */
class Producer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否满,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.size() ==
                        ProducerConsumerDemo.CAPACITY){
                    // 如果队列满,则等待消费者消费
                    try {
                        System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待消费者消费.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不满,则正常生产
                ProducerConsumerDemo.QUEUE.add(1);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒消费者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

/**
 * 消费者
 */
class Consumer implements Runnable{

    public void run() {
        while(true){
            synchronized (ProducerConsumerDemo.LOCK){
                // 检查队列是否空,推荐用while而不是if
                while(ProducerConsumerDemo.QUEUE.isEmpty()){
                    // 如果队列空,则等待生产者生产
                    try {
                        System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
                                Thread.currentThread().getName() + "】正在等待生产者生产.");
                        ProducerConsumerDemo.LOCK.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 如果队列不空,则正常消费
                ProducerConsumerDemo.QUEUE.remove(0);
                System.out.println("线程【" + Thread.currentThread().getName() +
                        "】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());

                // 唤醒生产者
                ProducerConsumerDemo.LOCK.notifyAll();
            }
        }
    }
}

2.案例

2.1.方法:sleep

方法简述:

1.让线程进入TIMED_WAITING状态

2.如果线程占有锁对象资源,不会释放锁

package com.anan.thread.threadmethod;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 线程方法sleep:
 *  1.让线程进入TIMED_WAITING状态
 *  2.如果线程占有锁对象资源,不会释放锁
 */
public class ThreadMethodSleepDemo {

    // 锁
    public final static Object LOCK = new Object();

    public static void main(String[] args) {
        // 创建Runnable对象
        Runnable r1 = new MyRunnable();

        // 创建两个线程对象
        Thread t1 = new Thread(r1,"thread-0");
        Thread t2 = new Thread(r1,"thread-1");

        // 启动线程
        t1.start();
        t2.start();

    }
}

/**
 * 实现Runnable接口,创建线程
 */
class MyRunnable implements Runnable{
    public void run() {
        System.out.println("【" + Thread.currentThread().getName() + "】准备休眠.");
        // 加锁,演示sleep不释放锁
        synchronized (ThreadMethodSleepDemo.LOCK){
            System.out.println("【" + Thread.currentThread().getName() + "】获取到锁.休眠进行中.");
            int time = 0;
            try {
                Random random = new Random();
                time = random.nextInt(6);
                TimeUnit.SECONDS.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("【" + Thread.currentThread().getName() + "】随机休眠:" +time+ "秒时间到.释放锁.");
        }
        System.out.println("【" + Thread.currentThread().getName() + "】结束休眠.");
    }
}

1

2.2.方法:join

方法简述:

1.方法join表示在一个线程中,加入另外一个线程

2.被加入线程,会等待【加入线程】执行完成

package com.anan.thread.threadmethod;

import java.util.concurrent.TimeUnit;

/**
 * 线程方法join:
 *      1.如果有线程加入我们,我们就等待加入线程执行完成
 */
public class ThreadMethodJoinDemo {

    public static void main(String[] args) throws InterruptedException{
        // 创建线程对象
        Runnable r1 = new MyRunnable1();
        Thread t1 = new Thread(r1,"thread-0");
        t1.start();

        // join方法
        t1.join();

        System.out.println("主线程main方法执行中.");

    }
}

/**
 * 实现Runnable接口,创建线程
 */
class MyRunnable1 implements Runnable{
    public void run() {
        for(int i = 0; i < 3; i++){
            System.out.println(Thread.currentThread().getName() +
                    "第:【" + i + "】次执行.");

            // 休眠10毫秒
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + "执行结束.");
    }
}

1

2.3.方法:yield

方法简述:

1.线程主动让出CPU执行时间

2.孔融让梨,和谐社会大家好

3.需要注意:这只是一种美德,不能对它产生依赖

package com.anan.thread.threadmethod;

/**
 * 线程方法yield:
 *      1.线程主动让出CPU执行时间
 *      2.孔融让梨,和谐社会大家好
 */
public class ThreadMethodYieldDemo {

    public static void main(String[] args) {
        // 创建两个线程
        Runnable r1 = new MyRunnable2();

        Thread t0 = new Thread(r1, "thread-0");
        Thread t1 = new Thread(r1, "thread-1");

        // 线程t0
        t0.start();

        // yield方法,线程t1
        t1.start();
        t1.yield();

    }
}

/**
 * 实现Runnable接口,创建线程
 */
class MyRunnable2 implements Runnable{
    public void run() {
        for(int i = 0; i < 3; i++){
            System.out.println("【" + Thread.currentThread().getName() +
                    "】第:【" + i + "】次执行.");

        }
        System.out.println("【" + Thread.currentThread().getName() +
                "】执行结束.");
    }
}

3

关于作者

王硕,网名信平,十多年软件开发经验,业余架构师,精通Java/Python/Go等,喜欢研究技术,著有《PyQt 5 快速开发与实战》《Python 3.* 全栈开发》,多个业余开源项目托管在GitHub上,欢迎微博交流。

Comments

Make a comment

Author: admin

Publish at: ...

关于作者

王硕,网名信平,十多年软件开发经验,业余架构师,精通 C/Java/Python/Go 等,喜欢读书,音乐和宅在家里。
Email: xujieiata@163.com

www.ultrapower.com ultrapower 王硕的博客,专注于研究互联网产品和技术,提供中文精品教程。