Java Multithreading 1: Overview of Processes and Threads

From: http://www.cnblogs.com/xrq730/p/4850883.html


processes and threads

When it comes to multithreading, we must first talk about the concepts of processes and threads.

process

A process can be understood as a basic running unit managed by the operating system. 360 browser is a process, WPS is also a process, ".exe" running in the operating system can be understood as a process

thread

A subtask that runs independently in a process is a thread. For example, when QQ.exe is running, there are many subtasks running, such as chat thread, friend video thread, download file thread and so on.

 

Why use multithreading

When used properly, threads can effectively reduce costs such as program development and maintenance, while improving the performance of complex applications. Specifically, the advantages of threads are:

1. Unleash the power of multiprocessors

Now that multi-processor systems are becoming more prevalent and prices are decreasing, even in low-end servers and interrupted desktop systems, multiple processors are often used, and this trend is further accelerated by increasing the clock frequency Performance has become increasingly difficult, and processor manufacturers are turning to placing multiple processor cores on a single chip. Just imagine that if there is only a single thread, the program on a dual-core processor system can only use half of the CPU resources, and on a system with 100 processors, 99% of the resources will be unavailable. Multithreaded programs can execute on multiple processors at the same time. If designed correctly, multithreaded programs can increase system throughput by increasing the utilization of processor resources.

2. Get higher throughput on uniprocessor systems

If the program is single-threaded, the processor will be idle while the program is waiting for some synchronous I/O operation to complete. In a multithreaded program, if one thread is waiting for an I/O operation to complete, another thread can continue running, allowing the program to continue running while the I/O is blocked.

3. Simplicity of modeling

By using threads, complex and asynchronous workflows can be further decomposed into a set of simple and synchronous workflows, each running in a separate thread and interacting at a specific synchronous location. We can achieve the above goals through some existing frameworks, such as Servlet and RMI, the framework takes care of the details such as request management, thread creation, load balancing, and dispatching requests to the right application components at the right time. Developers writing servlets do not need to know how many requests are being processed at the same time, nor do they need to know whether the input stream or output stream of the socket is blocked. way to handle this request as if it were a single-threaded program.

4. Simplified processing of asynchronous events

Server applications that accept multiple socket connection requests from remote clients are less difficult to develop if each connection is allocated its own thread and uses synchronous I/O. If an application performs a read operation on the socket and no data has arrived yet, the read operation will block until data arrives. In a single-threaded application, this means not only that the processing of the request will stall, but it also means that the processing of all requests will stall while the thread is blocked. To avoid this problem, single-threaded server applications must use non-blocking I/O, but this I/O is far more complex than synchronous I/O and is prone to errors. However, if each request has its own processing thread, blocking while processing one request will not affect the processing of other requests.

 

How to create a thread

There are two ways to create a thread:

1. Inherit Thread and override the run() method of the parent class.

复制代码
public class MyThread00 extends Thread
{        
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println(Thread.currentThread().getName() + "在运行!");
        }
    }
}
复制代码
复制代码
public static void main(String[] args)
{
    MyThread00 mt0 = new MyThread00();
    mt0.start();
        
    for (int i = 0; i < 5; i++)
    {
        System.out.println(Thread.currentThread().getName() + "在运行!");
    }
}
复制代码

看一下运行结果:

复制代码
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
Thread-0在运行!
main在运行!
复制代码

看到main线程和Thread-0线程交替运行,效果十分明显。

有可能有些人看不到这么明显的效果,这也很正常。所谓的多线程,指的是两个线程的代码可以同时运行,而不必一个线程需要等待另一个线程内的代码执行完才可以运行。对于单核CPU来说,是无法做到真正的多线程的,每个时间点上,CPU都会执行特定的代码,由于CPU执行代码时间很快,所以两个线程的代码交替执行看起来像是同时执行的一样。那具体执行某段代码多少时间,就和分时机制系统有关了。分时系统把CPU时间划分为多个时间片,操作系统以时间片为单位片为单位各个线程的代码,越好的CPU分出的时间片越小。所以看不到明显效果也很正常,一个线程打印5句话本来就很快,可能在分出的时间片内就执行完成了。所以,最简单的解决办法就是把for循环的值调大一点就可以了(也可以在for循环里加Thread.sleep方法,这个之后再说)。

2、实现Runnable接口。和继承自Thread类差不多,不过实现Runnable后,还是要通过一个Thread来启动:

复制代码
public class MyThread01 implements Runnable
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println(Thread.currentThread().getName() + "在运行!");
        }
    }
}
复制代码
复制代码
public static void main(String[] args)
{
    MyThread01 mt0 = new MyThread01();
    Thread t = new Thread(mt0);
    t.start();
        
    for (int i = 0; i < 5; i++)
    {
        System.out.println(Thread.currentThread().getName() + "在运行!");
    }
}
复制代码

效果也十分明显:

复制代码
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
main在运行!
Thread-0在运行!
复制代码

 

两种多线程实现方式的对比

看一下Thread类的API:

其实Thread类也是实现的Runnable接口。两种实现方式对比的关键就在于extends和implements的对比,当然是后者好。因为第一,继承只能单继承,实现可以多实现;第二,实现的方式对比继承的方式,也有利于减小程序之间的耦合。

因此,多线程的实现几乎都是使用的Runnable接口的方式。不过,后面的文章,为了简单,就用继承Thread类的方式了。

 

线程状态

虚拟机中的线程状态有六种,定义在Thread.State中:

1、新建状态NEW

new了但是没有启动的线程的状态。比如"Thread t = new Thread()",t就是一个处于NEW状态的线程

2、可运行状态RUNNABLE

new出来线程,调用start()方法即处于RUNNABLE状态了。处于RUNNABLE状态的线程可能正在Java虚拟机中运行,也可能正在等待处理器的资源,因为一个线程必须获得CPU的资源后,才可以运行其run()方法中的内容,否则排队等待

3、阻塞BLOCKED

如果某一线程正在等待监视器锁,以便进入一个同步的块/方法,那么这个线程的状态就是阻塞BLOCKED

4、等待WAITING

某一线程因为调用不带超时的Object的wait()方法、不带超时的Thread的join()方法、LockSupport的park()方法,就会处于等待WAITING状态

5、超时等待TIMED_WAITING

某一线程因为调用带有指定正等待时间的Object的wait()方法、Thread的join()方法、Thread的sleep()方法、LockSupport的parkNanos()方法、LockSupport的parkUntil()方法,就会处于超时等待TIMED_WAITING状态

6、终止状态TERMINATED

线程调用终止或者run()方法执行结束后,线程即处于终止状态。处于终止状态的线程不具备继续运行的能力


Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326825623&siteId=291194637