Thinking In Java 之 多线程 1

本文介绍了Java中多线程的应用技巧,包括使用Executor框架管理线程池、创建可返回结果的任务、设置线程优先级、守护线程的使用以及线程间的阻塞等待等关键概念。

Thinking In Java 之多线程

Using Executors

  1. The call to shutdown() prevents new task from being submitted to that Executor.
  2. Note that in any of the thread pools, existing threads are automatically reused when possible.
  3. A SingleThreadExecutor serializes the tasks that are submitted to it, and maintain its own (hidden) queue of pending task. SingleThreadExecutor to ensure that only one task at a time is running from any thread. This way, you don’t need to deal with synchronizing on the shared resource (and you won’t clobber the file system in the meantime).

Producing return values form tasks

class TaskWithResult implements Callable<String> {

    private int id;

    public TaskWithResult(int id) {
        this.id = id;
    }

    public String call() {
        return "result of TaskWithResult " + id;
    }

}

public class CallableDemo {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        ArrayList<Future<String>> results = new ArrayList<Future<String>>();
        for (int i = 0; i < 10; i++) {
            results.add(exec.submit(new TaskWithResult(i)));
        }
        for (Future<String> fs : results) {
            try {
                // get() blocks until completion:
                System.out.println(fs.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } finally {
                exec.shutdown();
            }
        }
    }
}

The overloaded Executors.callable() method tasks a Runnable and produces a Callable.

Sleeping

public class LiftOff implements Runnable {

    protected int countDown = 10;
    private static int taskCount = 0;//!
    private final int id = taskCount++;//!
    public LiftOff() {}
    public LiftOff(int countDown) {
        this.countDown = countDown;
    }

    public String status() {
        return "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!" ) + "),";
    }

    @Override
    public void run() {
        while(countDown-- > 0) {
            System.out.println(status());
            // I've done the important parts of my cycle and this would be a good
            // time to switch to another task for a while.
            Thread.yield();
        }

    }

}
public class SleepingTask extends LiftOff{

    public void run() {
        try {
            while(countDown-- > 0) {
                System.out.print(status());
                TimeUnit.MILLISECONDS.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0;i<5;i++) {
            exec.execute(new SleepingTask());
        }
        exec.shutdown();  
    }

}

Because exceptions won’t propagate across threads back to main(), you must locally handle any exceptions that arise within a task.

Priority

Lower-priority threads just tend to run less often.

public class SimplePrioroties implements Runnable{

    private int countDown = 5;
    private volatile double d;// No optimization
    private int priority;

    public SimplePrioroties(int priority) {
        this.priority = priority;
    }

    public String toString() {
        return Thread.currentThread() + ": " + countDown;
    }

    @Override
    public void run() {
        Thread.currentThread().setPriority(priority);//!
        while(true) {
            // An expensive, interruptable operation:
            for(int i=1;i<10000;i++) {
                d += (Math.E) / (double) i;
                if(i % 1000 == 0)
                    Thread.yield();
            }
            System.out.println(this);
            if(--countDown == 0) return ;
        }
    }

    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0;i<5;i++) {
            exec.execute(new SimplePrioroties(Thread.MIN_PRIORITY));
        }
        exec.execute(new SimplePrioroties(Thread.MAX_PRIORITY));
        exec.shutdown();
    }
}

You can get a reference to the Thread object that is driving a task, inside that task, by calling Thread.currentThread().
Note that the priority is set at the beginning of run(); setting it in the constructor would do no good since the Executor has not begun the task at that point.

Daemon thread

public class SimpleDaemon implements Runnable{

    @Override
    public void run() {
        try {
            while(true) {
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread() + " " + this);
            }
        } catch (InterruptedException e) {
            System.out.println("sleep() interrupted");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for(int i=0;i<10;i++) {
            Thread daemon = new Thread(new SimpleDaemon());
            daemon.setDaemon(true);
            daemon.start();
        }
        System.out.println("All daemon started");
        TimeUnit.MILLISECONDS.sleep(175);
    }

}

When all of the non-daemon threads complete, the program is terminated, killing all daemon threads in the process.

以下例子使用到了ThreadFactory,可与上面的例子做对比。

public class DaemonThreadFactory implements ThreadFactory{

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }

}
public class DaemonFromFactory implements Runnable{

    @Override
    public void run() {
        try {
            while(true) {
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread() + " " + this);
            }
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool(new DaemonThreadFactory());
        for(int i=0;i<10;i++) {
            exec.execute(new DaemonFromFactory());
        }
        System.out.println("All daemons started");
        TimeUnit.MILLISECONDS.sleep(500);
    }
}

——————————

public class DaemonsDontRunFinally {
    public static void main(String[] args) {
        Thread t = new Thread(new ADaemon());
        t.setDaemon(true);
        t.start();
    }
}

class ADaemon implements Runnable{

    @Override
    public void run() {
        try {
            System.out.println("Starting ADaemon");
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            System.out.println("Exiting via InterruptedException");
        }finally {
            System.out.println();
        }
    }

}

When you run this program, you’ll see that the finally clause is not executed, but if you comment out the call to setDaemon(), you’ll see the finally clause is executed.

Coding variations

即在构造器里启动自己

public class SimpleThread extends Thread {
    private int countDown = 5;
    private static int threadCount = 0;

    public SimpleThread() {
        // Store the Thread name:
        super(Integer.toString(++threadCount));
        start();
    }

    public String toString() {
        return "#" + getName() + "(" + countDown + "),";
    }

    public void run() {
        while(true) {
            System.out.print(this);
            if(--countDown == 0)
                return;
        }
    }

    public static void main(String[] args) {
        for(int i=0;i<5;i++) 
            new SimpleThread();
    }

}
public class SelfManager implements Runnable{

    private int countDown = 5;
    private Thread t = new Thread(this);

    public SelfManager() {
        t.start();
    }

    public String toString() {
        return Thread.currentThread().getName() + "(" + countDown + ")";
    }

    @Override
    public void run() {
        while(true) {
            System.out.println(this);
            if(--countDown == 0) {
                return;
            }
        }
    }

    public static void main(String[] args) {
        for(int i=0;i<5;i++) {
            new SelfManager();
        }
    }

}

This example is quite simple and therefore probably safe, but you should be aware that starting threads inside a constructor can be quite problematic, because another task might start executing before the constructor has completed, which means the task may be able to access the object in an unstable state.

Joining a thread

If a thread calls t.join() on another thread t, then the calling thread is suspended until the target thread t finished(when t.isAlive() is false).

class Sleeper extends Thread {

    private int duration;

    public Sleeper(String name, int sleepTime) {
        super(name);
        duration = sleepTime;
        start();
    }

    public void run() {
        try {
            sleep(duration);
        } catch (InterruptedException e) {
            System.out.println(getName() + " was interrupted. " + "isInterrupted():  " + isInterrupted());
            return;
        }
        System.out.println(getName() + "has awakened");
    }
}

class Joiner extends Thread{
    private Sleeper sleeper;
    public Joiner(String name, Sleeper sleeper) {
        super(name);
        this.sleeper = sleeper;
        start();
    }
    public void run() {
        try {
            sleeper.join();
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
        System.out.println(getName() + " join compeleted");
    }
}

public class Joining {
    public static void main(String[] args) {
        Sleeper 
            sleepy = new Sleeper("Sleepy", 1500),
            grumpy = new Sleeper("Grumpy", 1500);

        Joiner 
            doper = new Joiner("Doper", sleepy),
            doc = new Joiner("Doc", grumpy);
        grumpy.interrupt();
    }
}

运行结果:
这里写图片描述
When another thread calls interrupt() on this thread, a flag is set to indicate that the thread has been interrupted. However, this flag is cleared when the exception is caught, so the result will always be false inside the catch clause.

Nano-ESG数据资源库的构建基于2023年初至2024年秋季期间采集的逾84万条新闻文本,从中系统提炼出企业环境、社会及治理维度的信息。其构建流程首先依据特定术语在德语与英语新闻平台上检索,初步锁定与德国DAX 40成分股企业相关联的报道。随后借助嵌入技术对文本段落执行去重操作,以降低内容冗余。继而采用GLiNER这一跨语言零样本实体识别系统,排除与目标企业无关的文档。在此基础上,通过GPT-3.5与GPT-4o等大规模语言模型对文本进行双重筛选:一方面判定其与ESG议题的相关性,另一方面生成简明的内容概要。最终环节由GPT-4o模型完成,它对每篇文献进行ESG情感倾向(正面、中性或负面)的判定,并标注所涉及的ESG具体维度,从而形成具备时序特征的ESG情感与维度标注数据集。 该数据集适用于多类企业可持续性研究,例如ESG情感趋势分析、ESG维度细分类别研究,以及企业可持续性事件的时序演变追踪。研究者可利用数据集内提供的新闻摘要、情感标签与维度分类,深入考察企业在不同时期的环境、社会及治理表现。此外,借助Bertopic等主题建模方法,能够从数据中识别出与企业相关的核心ESG议题,并观察这些议题随时间的演进轨迹。该资源以其开放获取特性与连续的时间覆盖,为探究企业可持续性表现的动态变化提供了系统化的数据基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值