Basic concepts and implementation methods of multithreading

1. Basic concepts

Program: It is an ordered collection of instructions and data. It has no operational meaning and is a static concept.
Process: It is an execution process of executing a program, it is a dynamic concept. It is the unit of system resource allocation.

Usually a process can contain several threads. Thread is the unit of CPU scheduling and execution.
Many multithreads are simulated. Real multithreading refers to multiple CPUs, that is, multiple cores, such as servers.
If it is simulated multi-threading, that is, in the case of one CPU, the CPU can only execute one code at the same point in time. Because the switching is fast, there will be an illusion of simultaneous execution.

A thread is an independent execution path;
when the program is running, even if you do not create a thread yourself, there will be multiple threads in the background, such as the main thread and gc thread;
main() is called the main thread, which is the entrance of the system and is used for execution. The whole program:
In a process, if multiple threads are opened, the thread running is scheduled by the scheduler. The scheduler is
closely related to the operating system, and the sequence cannot be artificially interfered.
When operating on the same resource, there will be a problem of resource grabbing, and concurrency control needs to be added;
threads will bring additional overhead, such as cpu scheduling time and concurrency control overhead.
Each thread interacts in its own working memory. Improper memory control will cause data inconsistency

2. 3 ways to realize multithreading

The first method: inherit the Thread class, rewrite the run method (understand it)

The implementation code is as follows:

//创建多线程方式一:继承Thread类,重写run方法,调用start方法开启线程
public class TestThread1 extends Thread{
    
    
    @Override
    public void run(){
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            System.out.println("看代码--"+i);
        }
    }

    public static void main(String[] args) {
    
    
        //main线程,主线程

        //创建线程对象,并调用start()方法启动线程
        TestThread1 thread1 = new TestThread1();
        thread1.start();

        for (int i = 0; i < 1000; i++) {
    
    
            System.out.println("学习多线程--"+i);
        }
    }
}

The second method: implement the Runnable interface and rewrite the run method (emphasis)

The implementation code is as follows:

//创建多线程方式二:实现Runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class TestThread2 implements Runnable{
    
    
    @Override
    public void run(){
    
    
        for (int i = 0; i < 1000; i++) {
    
    
            System.out.println("看代码--"+i);
        }
    }

    public static void main(String[] args) {
    
    
        //main线程,主线程

        //创建Runnable接口的实现类对象
        TestThread2 testThread2 = new TestThread2();

        //创建线程对象,通过线程对象来开启我们的线程,代理
        Thread thread = new Thread(testThread2);
        thread.start();

        for (int i = 0; i < 1000; i++) {
    
    
            System.out.println("学习多线程--"+i);
        }
    }
}

The third method: to implement the Callable interface (you can understand it) to
implement the Callable interface, the return value type needs to be
rewritten, the call method needs to be thrown, the
target object is
created, and the execution service is created: ExecutorService ser = Executors.newFixedThreadPool(1);
Submit for execution: Futureresult1 = ser.submit(t1);
Get the result: boolean r1 = result1.get()
Shut down the service: ser.shutdownNow();

Code exercise-the tortoise and the hare:

//模拟龟兔赛跑
public class Race implements Runnable{
    
    

    //定义胜利者
    private static String winner;

    @Override
    public void run() {
    
    
        for (int i = 0; i <= 100; i++) {
    
    

            //模拟兔子休息。每隔10毫秒
            if (Thread.currentThread().getName().equals("兔子") && i%10==0){
    
    
                try {
    
    
                    Thread.sleep(10);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }

            //判断比赛是否结束
            boolean flag = gameOver(i);
            if(flag)
                break;
            System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");
        }
    }

    //判断是否完成比赛
    private boolean gameOver(int steps){
    
    
        if(winner != null) //已经有winner了
            return true;
        if(steps == 100){
    
    
            winner = Thread.currentThread().getName();
            System.out.println("winner is "+ winner);
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
    
    
        Race race = new Race();

        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

3. Thread method

setPriority(int newPriority)Change the thread priority.
static void sleep(long millis)Let the currently executing thread sleep for the specified number of milliseconds.
void join()Wait for the thread to terminate.
static void yield()Pause the currently executing thread object and execute other threads.
void interrupt()Interrupt the thread. Don’t use this to
boolean isAlive()test whether the thread is active.

Test thread priority (priority)

According to the results of multiple runs: the main thread runs first every time. And the other 3, randomly
known: the main thread priority is 5, not set (default) is also 5. The low priority is just the low probability of being called, it is not that the low priority will not be called, it all depends on the CPU scheduling.

Code exercise:

package com.lu.state;

//测试线程优先级
//根据多次运行结果:main线程每次是都是最先运行。而另外3个,随机
//可知:main线程优先级是5,不设置(默认)也是5。优先级低只是被调用的概率低,
//并不是优先级低就不会被调用了,这都要看CPU的调度
public class TestPriority{
    
    
    public static void main(String[] args) {
    
    
        //主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority = new MyPriority();
        Thread t0 = new Thread(myPriority);
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);

        //先设置优先级在启动
        t1.setPriority(1);
        t2.setPriority(10);

        t1.start();
        t2.start();
        t0.start();
    }
}
class MyPriority implements Runnable{
    
    
    @Override
    public void run() {
    
    
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

Daemon thread The
thread is divided into user thread and daemon thread. The
virtual machine must ensure that the user thread is executed. The
virtual machine does not need to wait for the daemon thread to execute. For
example, the background records operation logs, monitors memory, and waits for garbage collection.

Code exercise:

package com.lu.state;

//测试守护线程
//上帝守护你
public class TestDaemon {
    
    
    public static void main(String[] args) {
    
    
        God god = new God();
        You you = new You();

        Thread thread = new Thread(god);
        thread.setDaemon(true);//默认是false,表示是用户线程,正常的线程都是用户线程...

        thread.start();//上帝守护线程启动

        new Thread(you).start();//你,用户线程启动

    }
}

//上帝
class God implements Runnable{
    
    
    @Override
    public void run() {
    
    
        while (true){
    
    
            System.out.println("上帝保佑着你");
        }
    }
}

//你
class You implements Runnable{
    
    
    @Override
    public void run() {
    
    
        for (int i = 0; i < 36500; i++) {
    
    
            System.out.println("你一生都开心的活着");
        }
        System.out.println("goodbye world!");
    }
}

Guess you like

Origin blog.csdn.net/qq_42524288/article/details/105783409