多线程——初学总结

目录

一. 多线程概述

1.进程与线程

2.同步与异步

3.并发与并行

二. 实现多线程

1.通过继承Thread实现多线程

2.通过实现Runnable实现多线程

3.通过实现Callable实现多线程

三. Thread类常用方法

1.sleep(休眠)

2.currentThread调用当前线程的对象

3.interrupt标记线程中断

4.setDaemo设置守护线程

 四. 线程安全问题

1.线程不安全

2.线程安全 

1.同步代码块-synchronized

2.同步方法-synchronized

3.显示锁 -Lock

4.显示锁与隐式锁的区别

5.公平锁与非公平锁

五. 线程死锁问题 

六. 线程通信问题 

1.第一代代码(出现数据错乱)

2.第二代代码(出现重复操作) 

 3.第三代代码(正确代码)

七. 线程的六种状态 

八. 线程池 

1.定长线程池

2.单线程线程池

3.缓存线程池

4.周期性线程池

 九. Lambda表达式


一. 多线程概述

1.进程与线程

进程:进程是指一块内存中运行的应用程序(软件),现在有部分软件,一个软件就有多个进程,但是在学习过程中为了好理解,可以把一个进程当作一个独立工作的软件来理解。每个进程都有自己独立的空间(栈和堆),除非通过一些技术手段,否则两个进程之间没办法实现相互通信。

线程:线程是指一个程序中执行的任务,一个程序(进程)内有多个线程,每个线程都有自己独立的栈,共享堆内存,当一个进程中没有一个线程执行了,代表软件关闭,也就是说一个进程在执行,那么该进程中至少有一个线程在运行。

多线程:多线程就是指一个一个程序可以执行多个任务。

补充:多线程实际上是提高了运行效率,而不是速度,很多人在理解多线程时,都觉得多个任务执行是加快了速度,其实不然,原因在于:Java多线程的线程调度采用的是抢占式调度机制

解释:你的电脑是六核处理器的,则有12个大脑(cpu),则意味着你的电脑实际上只能在同一时刻执行12个任务,然而电脑上执行的任务是远远大于这个数量的,所以每个任务就会抢占时间偏,只是电脑运算速度很快,抢占时间偏时间很短几乎可以忽略,然后造成的所有任务同时进行的假象。实际上是优先级越高的抢占到的几率越大,优先级相同则抢到几率一样。

一个小问题1000个人操作服务器是同时执行速度快,还是排队执行快?这个问题会产生一个误区,这个误区就是刚才补充的问题。会有人觉得同时执行快,实际上是排队快。因为1000个人同时操作那么抢占时间偏那个过程也会花一点时间,因为要来回切换抢占,虽然可以忽略,但是在量很大的时候,也会占一点时间,所有实际上是排队,一个线程给它执行完快,但是效率低。           

2.同步与异步

同步:排队执行,效率低但安全

异步:同时执行,效率高但不安全

3.并发与并行

并发:同一时间段执行

并行:同一时刻执行

误区:服务器有5000个任务并行,大脑才多少个,就5000个同时执行了?所以不对

二. 实现多线程

1.通过继承Thread实现多线程

package com.java.test;

public class Test {
    public static void main(String[] args) {
        //创建子线程对象
        MyThread myThread = new MyThread();
        //开启子线程
        myThread.start();
        //主线程执行的任务
        for (int i=0;i<3;i++){
            System.out.println("疑是地上霜"+i);
        }
    }
}

class MyThread extends Thread{
    @Override
    //通过重写Thread类中的run方法来实现子线程要执行的任务
    public void run() {
        for (int i=0;i<3;i++){
            System.out.println("床前明月光"+i);
        }
    }
}

运行结果:
床前明月光0
床前明月光1
疑是地上霜0
床前明月光2
疑是地上霜1
疑是地上霜2

小贴士:每次运行输出的结果顺序都不同,因为每次抢占时间偏不同。

2.通过实现Runnable实现多线程

package com.java.test;

public class Test {
    public static void main(String[] args) {
        //创建任务对象
        MyRunnable m = new MyRunnable();
        //创建子线程,通过传入Runnable实例对象完成任务,没有重写Thread中的run方法
        Thread t = new Thread(m);
        //开启子线程
        t.start();
        //主线程任务
        for (int i=0;i<3;i++){
            System.out.println("疑是地上霜"+i);
        }
    }
}

class MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int i=0;i<3;i++){
            System.out.println("床前明月光"+i);
        }
    }
}

运行结果:

床前明月光0
床前明月光1
疑是地上霜0
疑是地上霜1
疑是地上霜2
床前明月光2

 小贴士:通过实现Runnable接口实现多线程达到了任务与线程分离,并且接口可以多实现,类不能多继承,所以使用Runnable有时候更方便,也不是不推荐使用Thread,根据需求进行操作。

3.通过实现Callable实现多线程

Runnable与Callable相同点:都是接口,都是创建Thread开启线程,

Runnable与Callable不同点:Callable中的call方法可以抛异常,使用Callable还可以通过创建

FutureTask 调用get方法获取返回值,使主线程等待子线程执行完毕再执行。

package com.java.test;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test5 {
    public static void main(String[] args) {
        //创建Callable
        Callable<Integer> c = new MyCallable();
        //创建FutureTask
        FutureTask<Integer> f = new FutureTask<>(c);
        //开启子线程
        new Thread(f).start();
        try {
            //调用get方法使主线程阻塞,等待子线程执行完毕,主线程才执行
            Integer integer = f.get();
            System.out.println("子线程执行完毕,获得返回值:"+integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //主线程任务
        for (int i=0;i<5;i++){
                System.out.println(Thread.currentThread().getName()+":疑是地上霜"+i);
            }
    }
}
class MyCallable implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+":床前明月光"+i);
        }
        return 100;
    }
}

运行结果:
Thread-0:床前明月光0
Thread-0:床前明月光1
Thread-0:床前明月光2
Thread-0:床前明月光3
Thread-0:床前明月光4
子线程执行完毕,获得返回值:100
main:疑是地上霜0
main:疑是地上霜1
main:疑是地上霜2
main:疑是地上霜3
main:疑是地上霜4

小贴士: 如果中间不调用f.get方法,则子线程和主线程还是抢占时间偏执行

三. Thread类常用方法

1.sleep(休眠)

public static void sleep​(long millis) throws InterruptedException
/*参数 
millis - 以毫秒为单位的睡眠时间长度 
异常 
IllegalArgumentException - 如果 millis值为负数 
InterruptedException - 如果有任何线程中断了当前线程。 抛出此异常时,将清除当前线程的中断状态 */

public static void sleep​(long millis, int nanos) throws InterruptedException
/*参数 
millis - 以毫秒为单位的睡眠时间长度 
nanos - 0-999999睡觉的额外纳秒 
异常 
IllegalArgumentException - 如果 millis值为负数,或者值 nanos不在 0-999999范围内 
InterruptedException - 如果有任何线程中断了当前线程。 抛出此异常时,将清除当前线程的中断状态*/


package com.java.test;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        for (int i=0;i<3;i++){
            System.out.println("床前明月光"+i);
            Thread.sleep(1000);
        }
    }
}

运行结果:

床前明月光0
床前明月光1
床前明月光2

每隔1秒打印一次 

2.currentThread调用当前线程的对象

public static Thread currentThread()
/*返回对当前正在执行的线程对象的引用*/
package com.java.test;

public class Test {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<3;i++){
                    System.out.println(Thread.currentThread().getName()+"床前明月光"+i);

                }
            }
        }.start();

        for (int i=0;i<3;i++){
            System.out.println(Thread.currentThread().getName()+"床前明月光"+i);

        }
    }
}

运行结果:

Thread-0床前明月光0
main床前明月光0
Thread-0床前明月光1
main床前明月光1
Thread-0床前明月光2
main床前明月光2

3.interrupt标记线程中断

public void interrupt()
/*中断此线程。 */
package com.java.test;

public class Test {
    public static void main(String[] args) {
        //创建子线程
        MyThread m = new MyThread();
        //开启子线程
        m.start();
        for (int i=0;i<3;i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"床前明月光"+i);
        }
        //子线程打上标记
        m.interrupt();
    }

}

class MyThread extends Thr
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值