6
回答
JAVA写的线程池,为何报异常
华为云实践训练营,热门技术免费实践!>>>   

为何会在取job的时候报错, jobs已经加锁了。

 

代码如下:

 

 

package com.thread;

public class RunableTest implements Runnable {
    
    private String name;
    
    public RunableTest(String name){
        this.name = name;
    }

    public void run() {
        System.out.println("RunableTest:"+name);

    }

}

 

package com.thread;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class DefaultThreadPool<Job extends Runnable> {

    // 线程池维护工作者线程的最大数量
    private static final int MAX_WORKER_NUMBERS = 10;
    // 线程池维护工作者线程的默认值
    private static final int DEFAULT_WORKER_NUMBERS = 5;
    // 线程池维护工作者线程的最小数量
    private static final int MIN_WORKER_NUMBERS = 1;
    // 维护一个工作列表,里面加入客户端发起的工作
    private final LinkedList<Job> jobs = new LinkedList<Job>();

    // 工作者线程的列表
    private final List<Worker> workers = Collections
            .synchronizedList(new ArrayList<Worker>());
    // 工作者线程的数量
    private int workerNum;
    // 每个工作者线程编号生成
    private AtomicLong threadNum = new AtomicLong();

    private Integer abc = new Integer(0);

    // 生成线程池
    public DefaultThreadPool() {
        this.workerNum = DEFAULT_WORKER_NUMBERS;
        initializeWorkers(this.workerNum);
    }

    public DefaultThreadPool(int num) {
        if (num < MIN_WORKER_NUMBERS) {
            this.workerNum = DEFAULT_WORKER_NUMBERS;
        } else {
            this.workerNum = num;
        }
        initializeWorkers(this.workerNum);
    }

    // 初始化每个工作者线程
    private void initializeWorkers(int num) {
        for (int i = 0; i < num; i++) {
            Worker worker = new Worker(i + "");
            // 添加到工作者线程的列表
            workers.add(worker);
            // 启动工作者线程
            Thread thread = new Thread(worker);
            thread.start();
        }
    }

    public void execute(Job job) {
        if (job != null) {
            // 根据线程的"等待/通知机制"这里必须对jobs加锁
            synchronized (jobs) {
                jobs.addLast(job);
                jobs.notify();
            }
        }
    }

    // 关闭线程池即关闭每个工作者线程
    public void shutdown() {
        for (Worker w : workers) {
            w.shutdown();
        }
    }

    // 增加工作者线程
    public void addWorkers(int num) {
        // 加锁,防止该线程还么增加完成而下个线程继续增加导致工作者线程超过最大值
        synchronized (jobs) {
            if (num + this.workerNum > MAX_WORKER_NUMBERS) {
                num = MAX_WORKER_NUMBERS - this.workerNum;
            }
            initializeWorkers(num);
            this.workerNum += num;
        }
    }

    // 减少工作者线程
    public void removeWorker(int num) {
        synchronized (jobs) {
            if (num >= this.workerNum) {
                throw new IllegalArgumentException("超过了已有的线程数量");
            }
            for (int i = 0; i < num; i++) {
                Worker worker = workers.get(i);
                if (worker != null) {
                    // 关闭该线程并从列表中移除
                    worker.shutdown();
                    workers.remove(i);
                }
            }
            this.workerNum -= num;
        }
    }

    public int getJobSize() {
        return workers.size();
    }

    // 定义工作者线程
    class Worker implements Runnable {
        // 表示是否运行该worker
        private volatile boolean running = true;

        private String name;

        public Worker(String name) {
            this.name = name;
        }

        public void run() {
            System.out.println(name + "线程初始化");
            while (running) {
                Job job = null;
                // 线程的等待/通知机制
                synchronized (jobs) {
                    if (jobs.isEmpty()) {
                        try {
                            System.out.println(name + "jobs wait....");
                            jobs.wait();// 线程等待唤醒
                        } catch (InterruptedException e) {
                            // 感知到外部对该线程的中断操作,返回
                            Thread.currentThread().interrupt();
                            return;
                        }
                    }

                    // 取出一个job
                    job = jobs.removeFirst();

                }

                // 执行job
                if (job != null) {
                    System.err.println(name + "线程执行操作");
                    job.run();
                }
            }
        }

        // 终止该线程
        public void shutdown() {
            running = false;
        }
    }
}
 

 

 

测试类:

public class MyThread{
    
    
    public static void main(String args[]) throws Exception{
        
        DefaultThreadPool<Runnable> dp = new DefaultThreadPool<Runnable>(10);
        dp.execute(new RunableTest("AA"));
        dp.execute(new RunableTest("BB"));
        dp.execute(new RunableTest("CC"));
        dp.execute(new RunableTest("DD"));
        dp.execute(new RunableTest("EE"));
        dp.execute(new RunableTest("FF"));
        dp.execute(new RunableTest("GG"));
        dp.execute(new RunableTest("HH"));     
    }

}

 

运行后

0线程初始化
1线程初始化
3线程初始化
0jobs wait....
3jobs wait....
4线程初始化
4jobs wait....
2线程初始化
2jobs wait....
6线程初始化
6jobs wait....
1jobs wait....
7线程初始化
7jobs wait....
5线程初始化
5jobs wait....
9线程初始化
9jobs wait....
8线程初始化
8jobs wait....
RunableTest:BB
RunableTest:CC
RunableTest:AA
7线程执行操作
7线程执行操作
0线程执行操作
2线程执行操作
6线程执行操作
1线程执行操作RunableTest:HH
RunableTest:GG
6jobs wait....
2jobs wait....
0jobs wait....

7线程执行操作
RunableTest:FF
1jobs wait....
RunableTest:EE
7jobs wait....
5线程执行操作
Exception in thread "Thread-3" Exception in thread "Thread-4" RunableTest:DD
5jobs wait....
java.util.NoSuchElementException
    at java.util.LinkedList.removeFirst(LinkedList.java:268)
    at com.thread.DefaultThreadPool$Worker.run(DefaultThreadPool.java:137)
    at java.lang.Thread.run(Thread.java:745)
java.util.NoSuchElementException
    at java.util.LinkedList.removeFirst(LinkedList.java:268)
    at com.thread.DefaultThreadPool$Worker.run(DefaultThreadPool.java:137)
    at java.lang.Thread.run(Thread.java:745)
 

为何会在   // 取出一个job  时候 获取为null , 不是已经加了锁了么?
 job = jobs.removeFirst();  

 

举报
KerryLi
发帖于8个月前 6回/293阅
顶部