public static void main(String[] args) { new MultiThreadTesterAbstract().start(); new SerialThreadTesterAbstract().start(); // multi thread take 5401ms // serial take 692ms } static abstract class AbstractTheadContextSwitchTester { static final int COUNT = 100_000_000; volatile int counter = 0; void increaseCounter() { counter++; } public abstract void start(); } static class MultiThreadTesterAbstract extends AbstractTheadContextSwitchTester { @Override public void start() { Stopwatch stopwatch = Stopwatch.createStarted(); Thread[] threads = new Thread[4]; for (int i = 0; i < 4; i++) { threads[i] = new Thread(new Runnable() { @Override public void run() { while (counter < COUNT) { synchronized (this) { if (counter < COUNT) { increaseCounter(); } } } } }); threads[i].start(); } for (int i = 0; i < 4; i++) { try { threads[i].join(); } catch (InterruptedException e) { e.printStackTrace(); } } log.info("multi thread take {}ms", stopwatch.elapsed(TimeUnit.MILLISECONDS)); } } static class SerialThreadTesterAbstract extends AbstractTheadContextSwitchTester { @Override public void start() { Stopwatch stopwatch = Stopwatch.createStarted(); for (int i = 0; i < COUNT; i++) { increaseCounter(); } log.info("serial take {}ms", stopwatch.elapsed(TimeUnit.MILLISECONDS)); } }
cs:系统的上下文切换频率
root@5d15480e8112:/# vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 3 0 0 693416 33588 951508 0 0 77 154 116 253 1 1 98 0 0
-w Report task switching activity (kernels 2.6.23 and later only). The following values may be displayed: UID The real user identification number of the task being monitored. USER The name of the real user owning the task being monitored. PID The identification number of the task being monitored. cswch/s Total number of voluntary context switches the task made per second. A voluntary context switch occurs when a task blocks because it requires a resource that is unavailable. nvcswch/s Total number of non voluntary context switches the task made per second. A involuntary context switch takes place when a task executes for the duration of its time slice and then is forced to relinquish the processor. Command The command name of the task.
root@5d15480e8112:/# pidstat -w -l -p 1 2 5 Linux 4.9.184-linuxkit (5d15480e8112) 09/16/2019 _x86_64_ (2 CPU) 07:28:03 UID PID cswch/s nvcswch/s Command 07:28:05 0 1 0.00 0.00 /bin/bash 07:28:07 0 1 0.00 0.00 /bin/bash 07:28:09 0 1 0.00 0.00 /bin/bash 07:28:11 0 1 0.00 0.00 /bin/bash 07:28:13 0 1 0.00 0.00 /bin/bash Average: 0 1 0.00 0.00 /bin/bash
可以通过Object对象的 wait、notify、notifyAll 来实现 线程间的通信 ,例如生产者-消费者模型
public class WaitNotifyTest { public static void main(String[] args) { Vector<Integer> pool = new Vector<>(); Producer producer = new Producer(pool, 10); Consumer consumer = new Consumer(pool); new Thread(producer).start(); new Thread(consumer).start(); } } @AllArgsConstructor class Producer implements Runnable { private final Vector<Integer> pool; private Integer size; @Override public void run() { for (; ; ) { try { produce((int) System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } } private void produce(int i) throws InterruptedException { while (pool.size() == size) { synchronized (pool) { pool.wait(); } } synchronized (pool) { pool.add(i); pool.notifyAll(); } } } @AllArgsConstructor class Consumer implements Runnable { private final Vector<Integer> pool; @Override public void run() { for (; ; ) { try { consume(); } catch (InterruptedException e) { e.printStackTrace(); } } } private void consume() throws InterruptedException { synchronized (pool) { while (pool.isEmpty()) { pool.wait(); } } synchronized (pool) { pool.remove(0); pool.notifyAll(); } } }