多线程 摘要

Background

Concurrency Hanlding

  • Listener & Worker :
    • Listener : to listen and accept user request;
    • Worker : to handle and respond to user request;
  • Single Process : handle only one request at a given time;
    • No Concurrency
  • Multi Processes : handle multiple requests at a given time;
    • Examples : FTP, Postgres, ancient WebServer (HTTP)
    • Limited Concurrency due to Heavy Resource Consumption
      • Dedicated memory
      • Cost on create and destory processes;
  • Multi Threads : handle multiple requests at a given time; 
    • Improved Concurrency due to Light Resource Consumption
      • Shared Memory (however Thread Synchronization)
      • Cost on create and descory threads is less than processes;
  • Further Optimization : Reduce the cost of create/destory process/threads
    • Pooling processes/threads;
  • Further Optimization : Reduce context switching cost
    • NIO - Selector;

Long Connections 

  • Result in Long Standing Processes/Threads and result in heavy resource consumption.
    • Cost : Threads - 1M; Context Switch;
    • Scale Out : use multiple servers;
    • Scale Up : reuse threads for multiple requests/connections, 
      • Scenarios : Thread is not fully utilized, i.e. most time idle - waiting for I/O activities;
      • Example : excessive amount of connections, yet less data transferred; ChatApp;

Thread

Declaration

Extend Thread class OR Implement Runnable Interface; And override run() function;

// Thread doing nothing, i.e. empty run()
new Thread().start();

// Thread doing nothing, i.e. empty run()
Thread thread = new Thread();
thread.start();

// Thread doing what is specified in ChileThread.run();
Thread thread = new ChildThread();
thread.start();

// Thread doing what is specified in objImplementRunnable.run();
Thread thread = new Thread(objImplementRunnable);
thread.start();

// No thread, but local (the same thread) method call;
Thread thread = new ChildThread();
thread.run();

Return Value

Race Condition

Cannot rely on the sequence of method invocation to assess the sequence of method completion, because sequence of Thread execution is not controllable.

public class Something {
    public void masterThread() {
        Thread worker = new WorkerThread();
        worker.start();

        // some other processing
        ...
    
        // RACE CONDITION : don't know if WorkerThread has run and completed;
        worker.getResult();
    }
}

public class WorkerThread() extends Thread {
    private int param1;
    private int param2;
    private int result;

    WorkerThread(int x, int y) {
        this.param1 = x;
        this.param2 = y;
    }

    @override
    public void run() {
        result = param1 + param2;
    }

    public int getResult() {
        return result;
    }
}

Master to POLL

Polling the status flag in the worker process, retrive the result only after flag is set; Problem is that the POLLING in master consume a lot of CPU power, and WorkerThread may not even get the opportunity to run;

public class Something {
    public void masterThread() {
        Thread worker = new WorkerThread();
        worker.start();

        // some other processing
        ...

        // POLLING : check the flag in WorkerThread;
        while (true) {
            if (worker.getWorkDone()) {
                worker.getResult();
                break;
            }
        }
    }
}

public class WorkerThread() extends Thread {
    private int param1;
    private int param2;
    private int result;
    // add a flag, indicating if work done
    private boolean workDone;

    WorkerThread(int x, int y) {
        this.param1 = x;
        this.param2 = y;
        workDone = false;
    }

    @override
    public void run() {
        result = param1 + param2;
        // there might be the issue of code resequencing by JVM;
        workDone = true;
    }

    public int getResult() {
        return result;
    }

    // method allowing master to poll and retrieve work status
    public boolean getWorkDone() {
        return workDone;
    }
}

Worker to CALLBACK

WorkerThread to callback a method exposed by MasterThread to send the result back, at the end of its run() function; This callback exposed by MasterThread can be either static callback or instance callback. In case of instance callback, the reference of the MasterThread has to be passed over to the WorkerThread;

public class Something {
    public void masterThread() {
        Thread worker = new WorkerThread();
        worker.start();
        // some other processing
        ...
    }

    // Address/method for worker to CALLBACK 
    public static void callBackAddress(int result) {
        ...
    }
}

public class WorkerThread() extends Thread {
    private int param1;
    private int param2;

    WorkerThread(int x, int y) {
        this.param1 = x;
        this.param2 = y;
    }

    @override
    public void run() {
        int result = param1 + param2;

        // CALLBACK : Send the result via CALLBACK
        Something.callBackAddress(result);
    }
}

Future, Callable & Executor 

Introduced in Java5, Future/Callable provide a new approach for Master to get the result from Worker thread, which fundementally relies on CALLBACK mechanism. Future.get() blocks until it gets the result from WorkerThread.

public class Something {
    public void masterThread() {
        // create a callable task
        WorkerThread task = new WorkerThread(x, y);
        // create a threadPool
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        // execute task using ThreadPool; Use Future to get the RESULT - actually a CALLBACK address;
        Future<Integer> result = threadPool.submit(task);

        // some other processing
        ...

        // get Result - BLOCKED until result is available;
        Integer result = result.get();
    }
}

public class WorkerThread() extends Callable<Integer> {
    private int param1;
    private int param2;

    WorkerThread(int x, int y) {
        this.param1 = x;
        this.param2 = y;
    }

    @override
    public Integer call() {
        int result = param1 + param2;
        return result;
    }
}

Scheduling

Not an issue if I/O heavy, since most likely threads will be blocked for I/O activities. However, if computation heavy, CPU will more likely to be the critical resources, with many threads to compete to get CPU to run their code, which may leads to THREAD STARVATION.

Priority

Java : 0 ~ 10, with 5 being the default; However, not all OS support 11 priorities, for example, Windows only support 7. Java Thread Priority Constants

public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;

Preemptive

Java use Preemptive scheduling :

  • Preemptive : Scheduler determine if there is another thread that deserve CPU time, if yes, switch to the other one;
  • Cooperative : Scheduler wait the current thread to pause and release the CPU. (could cause more starvation);

Pause Condition

TypeDescriptionRelease Obtaind Lock?
Block
  • Wait to obtain resources; I/O and Lock. 
  • READY only after resources are obtained;
No
Yield
  • Give up CPU to higher priority thread.
  • READY immediately
No
Sleep
  • Give up CPU to others, regardless if there is *others* or not, simply sleep().
  • READY after specified elapsed
  • READY if interrput() is called
No
Join
  • Give up CPU to the joining thread
  • READY after specified time elapsed
  • READY after joining thread complete
  • READY if interrput() is called
No
Object.Wait()
  • Give up CPU to others
  • READY after specified time elapsed
  • READY if interrupt() is called
  • READY if notified and obtained lock on the Object

YES : Lock ob Object

No : others

Finish

run() completesYes

Synchronization

Two threads access the shared resources; Need to ensure their access is in proper sequence.

Approach

  • sychronized
  • refain from using shared resources
  • ThreadLocal
  • automatic

Deadlock

转载于:https://my.oschina.net/u/3551123/blog/1023562

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JMeter是一个功能强大的Java应用程序,可以用来对Web应用程序进行性能测试。其中一个主要的功能就是多线程并发测试。 以下是使用JMeter进行多线程并发测试的步骤: 1. 安装JMeter 首先需要安装JMeter,可以从官网下载最新版本的JMeter。 2. 创建测试计划 在JMeter中,测试计划是测试的最高层次。打开JMeter并创建一个新的测试计划,可以通过菜单栏中的File -> New -> Test Plan来创建。 3. 添加线程组 线程组是测试计划中最重要的元素之一,用于设置并发用户数等参数。右键单击测试计划,选择Add -> Threads(Users) -> Thread Group来添加线程组。 在线程组中,需要设置以下参数: - Number of Threads: 并发用户数,即同时发送请求的用户数量。 - Ramp-Up Period: 线程启动的时间间隔,即每个线程启动之间的时间间隔。 - Loop Count: 每个线程执行的次数。 4. 添加HTTP请求 在线程组中添加HTTP请求,可以通过右键单击线程组,选择Add -> Sampler -> HTTP Request来添加。 在HTTP请求中,需要设置以下参数: - Server Name or IP: 被测试的Web服务器的主机名或IP地址。 - Protocol: 使用的协议,HTTP或HTTPS。 - Path: 要请求的资源的路径。 - Method: 请求方法,GET或POST等。 - 参数:请求中所需的参数。 5. 添加监听器 监听器用于收集测试结果并将其以可视化或文本格式显示。右键单击线程组,选择Add -> Listener来添加监听器。 在监听器中,可以选择以下一种或多种监听器: - Summary Report: 显示测试结果的摘要信息。 - Graph Results: 以图表形式显示测试结果。 - View Results Tree: 显示每个请求的详细信息。 - Assertion Results: 显示断言的结果。 6. 运行测试 设置好测试计划、线程组、HTTP请求和监听器后,即可开始运行测试。可以通过菜单栏中的Run -> Start或点击工具栏中的绿色三角形按钮来运行测试。 7. 查看测试结果 测试运行完成后,可以在监听器中查看测试结果。可以通过Summary Report、Graph Results、View Results Tree等监听器来查看测试结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值