多线程的基本概念和实现方法

1、基本概念

程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
进程:则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。

通常一个进程中可以包含若干个线程。线程是CPU调度和执行的单位
很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。
如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换很快,所以会有同时执行的错觉。

线程就是独立的执行路径;
在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
main()称之为主线程,为系统的入口,用于执行整个程序;
在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与
操作系统紧密相关的,先后顺序是不能人为的干预的。
对同一份资源操作时, 会存在资源抢夺的问题,需要加入并发控制;
线程会带来额外的开销, 如cpu调度时间,并发控制开销。
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

2、实现多线程的3种方法

第一种方法:继承Thread类,重写run方法(了解即可)

实现代码如下:

//创建多线程方式一:继承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);
        }
    }
}

第二种方法:实现Runnable接口,重写run方法(重点)

实现代码如下:

//创建多线程方式二:实现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);
        }
    }
}

第三种方法:实现Callable接口(了解即可)
实现Callable接口,需要返回值类型
重写call方法,需要抛出异常
创建目标对象
创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
提交执行:Futureresult1 = ser.submit(t1);
获取结果:boolean r1 = result1.get()
关闭服务:ser.shutdownNow();

代码练习–龟兔赛跑:

//模拟龟兔赛跑
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、线程方法

setPriority(int newPriority) 更改线程优先级
static void sleep(long millis) 让当前正在执行的线程休眠指定的毫秒数
void join() 等待该线程终止
static void yield() 暂停当前正在执行的线程对象,并执行其他线程
void interrupt() 中断线程,别用这个
boolean isAlive() 测试线程是否处于活动状态

测试线程优先级(priority)

根据多次运行结果:main线程每次是都是最先运行。而另外3个,随机
可知:main线程优先级是5,不设置(默认)也是5。优先级低只是被调用的概率低, 并不是优先级低就不会被调用了,这都要看CPU的调度。

代码练习:

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)线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如,后台记录操作日志,监控内存,垃圾回收等待

代码练习:

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!");
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42524288/article/details/105783409
今日推荐