精华内容
下载资源
问答
  • 一、线程的理解 ...多线程对于那些I/O受限的程序特别适用。 二、线程分类: 内核线程:由操作系统内核创建和撤销。 用户线程:不需要内核支持而在用户程序中实现的线程。 三、线程的生命周期 一个线程在

    一、线程的理解
    线程是"轻量级""的,一个进程中的线程使用同样的地址空间,且共享许多资源。启动线程的时间远远小于启动进程的时间和空间,而且,线程间的切换也要比进程间的切换快得多。由于使用同样的地址空间,所以线程之间的数据通信比较方便,一个进程下的线程之间可以直接使用彼此的数据。当然,这种方便性也会带来一些问题,特别是同步问题。。
    多线程对于那些I/O受限的程序特别适用。

    二、线程分类:
    内核线程:由操作系统内核创建和撤销。
    用户线程:不需要内核支持而在用户程序中实现的线程。

    三、线程的生命周期
    在这里插入图片描述
    一个线程在其生命周期内,会在不同的状态之间转换。在任何一个时刻,线程总是处于某种线程状态中。虽然不同的操作系统可以实现不同的线程模型,定义不同的线程状态,但是总的说来,一个线程模型中下面几种状态是通用的。

    1、线程的创建:t=threading.Thread()
    2、就绪状态:已经获得了除CPU之外的其他资源,正在参与调度,等待被执行,当调度完成之后,立即运行
    3、启动状态:获得了CPU时间片段,正在运行
    4、等待\阻塞状态:遇到time.sleep()时,会阻塞,暂时不参与调度,等待事件发生
    5、中止状态:线程运行结束,run函数运行结束,等待系统回收其线程资源。

    四、函数创建线程
    在这里插入图片描述
    执行结果:
    在这里插入图片描述
    四、类创建线程
    **加粗样式**
    t=MyThread(name=s[i]) 创建线程,里面的参数代表线程的名字,如果不传,系统会默认有一个名字
    五、多线程之得到线程的数量
    在这里插入图片描述
    执行结果
    在这里插入图片描述
    count=len(threading.enumerate()) 获得当前运行的线程的数量
    为什么线程一开始为6呢?
    5个子线程+1个主线程

    展开全文
  • java--第10章 多线程

    千次阅读 2021-01-09 16:19:05
    掌握多线程的编程。 实验内容: 1.通过继承Thread类创建线程。 2.通过实现Runnable接口创建线程。 3.线程优先级操作。 4.用两个线程玩猜数字的游戏。 实验步骤: 1.通过继承Thread类创建一个实现睡眠...

    实验目的:

          1.理解解线程的概念及线程的生命周期。

           2.掌握多线程的编程。

    实验内容:

           1.通过继承Thread类创建线程。

           2.通过实现Runnable接口创建线程。

           3.线程优先级操作。

           4.用两个线程玩猜数字的游戏。

    实验步骤:

    1.通过继承Thread类创建一个实现睡眠(时间在1~5秒)功能的线程,显示它的睡眠时间及其线程名称。

    源代码:

     

    package homework.实验10_多线程;
    
    public class sy10_1 {
        public static void main(String[] args) {
            Runner1 r = new Runner1();
            r.start();
            for (int i = 0; i < 3; i++) {
                if(i==2){
                    try {
                        Runner1.sleep(1000); //此处是类名.sleep()
    
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Runner1.currentThread().getName()+"当前运行的线程名称: "+ i);
            }
        }
    }




     

    class Runner1 extends Thread{
        public void run() {
            for (int i = 0; i < 5; i++) {
                if(i==4){
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println(Runner1.currentThread().getName()+"当前运行的线程名称: "+ i);
            }
        }
    }
    
    

    2.通过实现Runnable接口创建线程,要求产生三个线程对象,并分别设置三个线程的休眠时间:线程A休眠1秒,线程B休眠2秒,线程C休眠3秒。

    源代码:

    package homework.实验10_多线程;
    
    public class sy10_2 {
        public static void main(String[] args){
            new Thread(new Sleep("线程A", 1000)).start();
            new Thread(new Sleep("线程B", 2000)).start();
            new Thread(new Sleep("线程C", 3000)).start();
        }
    }
    
    class Sleep  implements Runnable{
        public long time;
        public String name;
    
        public Sleep(String name, long time){
            this.name = name;
            this.time = time;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                Thread.sleep(this.time);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(this.name+"休眠"+this.time+"毫秒");
        }
    
    }
    
    

     

    3.创建三个线程,使得其中一个线程的优先级最高,一个线程的优先级最低,一个线程的优先级介于两者之间。要求显示各线程的名称及其优先级。

    源代码:

    package homework.实验10_多线程;
    
    public class sy10_3 {
        public static void main(String[] args){
            Thread t1 = new Thread(new PriThread());
            Thread t2 = new Thread(new PriThread());
            Thread t3 = new Thread(new PriThread());
            t1.setPriority(Thread.MAX_PRIORITY);
            t2.setPriority(6);
            t3.setPriority(Thread.MIN_PRIORITY);
            t1.start();
            t2.start();
            t3.start();
        }
    }
    
    
    class PriThread implements Runnable{
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.println(Thread.currentThread().getName()+"的优先级是:"
                    +Thread.currentThread().getPriority()+"");
        }
    
    }
    
    

    4. 用两个线程玩猜数字的游戏:第一个线程负责随机给出1~100之间的一个整数,第二个线程负责猜出这个数。要求每当第二个线程给出自己的猜测后,第一个线程都会提示“猜小了”、“猜大了”或“猜对了”。

    源代码:

    package homework.实验10_多线程;
    
    import java.util.*;
    import java.util.Random;
    
    public class sy10_4{
    
        public static void main(String[] args) {
            number num=new number("线程一");
            num.start();
            guess gue=new guess("线程二");
            gue.start();
        }
    
    }
    //给出整数的线程
    class number extends Thread{
        String name1;
        private static int n;
        number(String name){
            name1=name;
        }
        public void run() {
            //获取1~100的随机数
            Random random=new Random();
            n=random.nextInt(100);
            System.out.println(name1+"给出的数字为:"+n);
        }
        //猜数字(静态方法,可通过类名调用)
        public static String guessnum(int m) {
            if(m<n) {
                return "猜小了";
            }else if(m>n){
                return "猜大了";
            }else return "猜对了";
        }
    }
    //猜数线程
    class guess extends  Thread{
        String name2;
        //最大值和最小值
        private int min=0,max=100,nownum;
        //比较结果
        String Result;
        guess(String name){
            name2=name;
        }
        //获取比较结果
        public String getGuess() {
            return Result;
        }
        public void run() {
            while(true) {
                try{
                    Thread.sleep(2000);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                Random ran=new Random();
                //当前猜的数字(最大值和最小值之间的数)
                nownum=min+ran.nextInt(max-min);
                //调用给出整数的线程 的猜数字方法guessnum,
                Result=number.guessnum(nownum);
                if(Result.equals("猜小了")) {
                    min=nownum;
                    System.out.println("线程二猜的数字是:"+nownum+"---猜小了");
                }else if(Result.equals("猜大了")) {
                    max=nownum;
                    System.out.println("线程二猜的数字是:"+nownum+"---猜大了");
                }else {
                    System.out.println("线程二猜的数字是:"+nownum+"---猜对了,结果是"+nownum);
                    System.exit(0);
                }
    
            }
        }
    }

     

    运行结果截图:

     

    实验小结

         进程与线程

          进程是程序的一次动态执行过程,它需要经历从代码加载,代码执行到执行完毕的一个完整的过程,这个过程也是进程本身从产生,发展到最终消亡的过程。多进程操作系统能同时达运行多个进程(程序),由于 CPU 具备分时机制,所以每个进程都能循环获得自己的CPU 时间片。由于 CPU 执行速度非常快,使得所有程序好像是在同时运行一样。

     

          多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位。线程是比进程更小的执行单位,线程是进程的基础之上进行进一步的划分。所谓多线程是指一个进程在执行过程中可以产生多个更小的程序单元,这些更小的单元称为线程,这些线程可以同时存在,同时运行,一个进程可能包含多个同时执行的线程。

     

    Java中线程实现的方式

          在 Java 中实现多线程有两种手段,一种是继承 Thread 类,另一种就是实现 Runnable 接口。

    实现Runnable接口例子:

    class MyThread implements Runnable{ // 实现Runnable接口,作为线程的实现类
    
        private String name ;       // 表示线程的名称
    
        public MyThread(String name){
    
            this.name = name ;      // 通过构造方法配置name属性
    
        }
    
        public void run(){  // 覆写run()方法,作为线程 的操作主体
    
            for(int i=0;i<10;i++){
    
                System.out.println(name + "运行,i = " + i) ;
    
            }
    
        }
    
    };
    
    public class RunnableDemo01{
    
        public static void main(String args[]){
    
            MyThread mt1 = new MyThread("线程A ") ;    // 实例化对象
    
            MyThread mt2 = new MyThread("线程B ") ;    // 实例化对象
    
            Thread t1 = new Thread(mt1) ;       // 实例化Thread类对象
    
            Thread t2 = new Thread(mt2) ;       // 实例化Thread类对象
    
            t1.start() ;    // 启动多线程
    
            t2.start() ;    // 启动多线程
    
        }
    
    };

     

    实现Thread接口

    class MyThread extends Thread{  // 继承Thread类,作为线程的实现类
    
        private String name ;       // 表示线程的名称
    
        public MyThread(String name){
    
            this.name = name ;      // 通过构造方法配置name属性
    
        }
    
        public void run(){  // 覆写run()方法,作为线程 的操作主体
    
            for(int i=0;i<10;i++){
    
                System.out.println(name + "运行,i = " + i) ;
    
            }
    
        }
    
    };
    
    public class ThreadDemo02{
    
        public static void main(String args[]){
    
            MyThread mt1 = new MyThread("线程A ") ;    // 实例化对象
    
            MyThread mt2 = new MyThread("线程B ") ;    // 实例化对象
    
            mt1.start() ;   // 调用线程主体
    
            mt2.start() ;   // 调用线程主体
    
        }
    
    };

     

           从程序可以看出,现在的两个线程对象是交错运行的,哪个线程对象抢到了 CPU 资源,哪个线程就可以运行,所以程序每次的运行结果肯定是不一样的,在线程启动虽然调用的是 start() 方法,但实际上调用的却是 run() 方法定义的主体。

     

    线程的状态变化

          要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有5种状态,即创建,就绪,运行,阻塞,终止。

     

    创建:Thread thread=new Thread()

    就绪:调用该线程的 start() 方法就可以启动线程。

    运行:当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。此时,自动调用该线程对象的 run() 方法。run() 方法定义该线程的操作和功能。

    阻塞:调用sleep(),suspend(),wait() 等方法,线程都将进入阻塞状态

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

     

          在 Java 的线程操作中,所有的线程在运行前都会保持在就绪状态,那么此时,哪个线程的优先级高,哪个线程就有可能会先被执行。

     

    展开全文
  • #include <thread> #include <vector> using namespace std; class my_class { public: ... // C++11之前:产生条件竞争 一个线程正在初始化变量,在未完成前其他线程也开始初始化 // C+.
    #include <thread>
    #include <vector>
    
    using namespace std;
    
    class my_class {
    public:
        my_class() {};
        ~my_class() {};
        string info;
    };
    
    my_class& get_my_class_instance()
    {
        // C++11之前:产生条件竞争 一个线程正在初始化变量,在未完成前其他线程也开始初始化
        // C++11:初始化及定义完全在一个线程中发生,并且没有其他线程可在初始化完成前对其进行处理
        static my_class instance[10000000];      
        instance[9999].info = "info message";    
        return instance[9999];
    }
    
    int main() {
        vector<thread> threads;
        for (int i = 0; i < 10; ++i) {
            threads.push_back(thread(get_my_class_instance));
        }
        for_each(threads.begin(), threads.end(), mem_fn(&thread::join));
        return 0;
    }

     

    展开全文
  • 1、多线程的创建注意:线程开启不一定立即执行,由CPU调度执行1.1创建方式一继承Thread类,重写run()方法,调用start()方法开启线程。package SunThread;public class Thread_01 extends Thread{@Overridepublic ...

    1、多线程的创建

    注意:线程开启不一定立即执行,由CPU调度执行

    1.1创建方式一

    继承Thread类,重写run()方法,调用start()方法开启线程。

    package SunThread;

    public class Thread_01 extends Thread{

    @Override

    public void run() {

    //run方法线程体

    for (int i = 0; i < 20; i++) {

    System.out.println("我在写代码!");

    }

    }

    public static void main(String[] args) {

    //main线程,主线程

    //创建线程对象

    Thread_01 thread_01 = new Thread_01();

    //调用start开启线程

    thread_01.start();

    for (int i = 0; i < 20; i++) {

    System.out.println("我在学JAVA");

    }

    }

    }

    1518027f5925b723d6e905790139c748.png

    多次运行发现(最好修改循环输出次数多一点),输出结果一般会不同,原因就是CPU在进行线程的调度。

    1.2创建方式二(建议使用)

    实现Runnable接口,重写run()方法,实现接口需要丢入Runnable接口实现类,调用start()方法开启线程。

    package SunThread;

    public class Thread_03 implements Runnable{

    @Override

    public void run() {

    //run方法线程体

    for (int i = 0; i < 20; i++) {

    System.out.println("我在写代码");

    }

    }

    public static void main(String[] args) {

    //main线程,主线程

    //创建ruunnable实现类对象

    Thread_03 thread_03 = new Thread_03();

    //创建线程对象通过线程对象实现我们的接口类

    //Thread thread = new Thread(thread_03);

    //thread.start();

    new Thread(thread_03).start();//与上两行实现的结果是一样的

    for (int i = 0; i < 100; i++) {

    System.out.println("我在学JAVA");

    }

    }

    }

    1cd6023ce8c74bd361e1ccd01b40281b.png

    推荐使用:实现Runable()接口,因为可以有效的避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用

    1.3创建方式三(不经常使用)

    ​与使用runnable方式相比,callable功能更强大些:call方法可以有返回值,方法可以抛出异常,支持泛型的返回值,需要借助FutureTask类,获取返回结果等。

    运用三个线程下载网络图片的方式,对Callable实现接口类的方式进行解释,(代码直接复制运行不了)。

    package SunThread;

    import org.apache.commons.io.FileUtils;

    import java.io.File;

    import java.io.IOException;

    import java.net.URL;

    import java.util.concurrent.*;

    public class Thread_05 implements Callable {

    private String url;//下载的网络图片地址

    private String name;//保存的文件名

    public Thread_05(String url, String name) {

    this.url = url;

    this.name = name;

    }

    @Override

    public Boolean call() throws Exception {

    WebDownloader webDownloader = new WebDownloader();

    webDownloader.Downloader(url,name);

    System.out.println("文件name为"+name);

    return true;

    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

    //new 3个Callable接口的对象

    Thread_05 t1 = new Thread_05("https://img-blog.csdnimg.cn/20201029222157503.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTl9fQ0dK,size_16,color_FFFFFF,t_70#pic_center","1.jpg");

    Thread_05 t2 = new Thread_05("https://img-blog.csdnimg.cn/20201029222523262.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTl9fQ0dK,size_16,color_FFFFFF,t_70#pic_center","2.jpg");

    Thread_05 t3 = new Thread_05("https://img-blog.csdnimg.cn/20201029222403840.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1NVTl9fQ0dK,size_16,color_FFFFFF,t_70#pic_center","3.jpg");

    //创建固定线程个数为3个的线程池

    ExecutorService executorService = Executors.newFixedThreadPool(3);

    //提交执行线程,最多3个

    Future s1 = executorService.submit(t1);

    Future s2 = executorService.submit(t2);

    Future s3 = executorService.submit(t3);

    //获取相应的结果

    boolean rs1=s1.get();

    boolean rs2=s2.get();

    boolean rs3=s3.get();

    //关闭线程池

    executorService.shutdown();

    }

    }

    //具体的下载方法,使用时需要导入commons—IO-2.6.jar包

    class WebDownloader{

    public void Downloader(String url,String name){

    try {

    FileUtils.copyURLToFile(new URL(url),new File(name));

    } catch (IOException e) {

    e.printStackTrace();

    }

    }

    }

    8d2dc83e224ca28e6c599ac0475dab12.png

    注:中间并发进行的接口对象,根据自己需要进行修改。

    2、线程五大状态

    2.1线程的停止(stop)

    1.建议线程正常停止―>利用次数,不建议死新环.

    2.建议使用标志位--->设置一个标志位

    3.不要使用stop或者destroy等过时或者JDK不建议使用的方法

    package SunThread;

    //测试线程停止

    public class Threadstop_01 implements Runnable{

    private boolean flag=true;

    @Override

    public void run() {

    int i=0;

    while (flag){

    System.out.println("我在测试线程停止"+i++);

    }

    }

    public void stop(){

    this.flag=false;

    }

    public static void main(String[] args) {

    Threadstop_01 threadstop_01 = new Threadstop_01();

    new Thread(threadstop_01).start();

    for (int i = 0; i < 1000; i++) {

    System.out.println("main"+i);

    if(i==900)

    {

    threadstop_01.stop();

    System.out.println("线程停止了");

    }

    }

    }

    }

    99a24f56d6b6c4a29119e29a0209a35d.png

    2.2线程的休眠(sleep)

    1、sleep(时间)指定当前线程阻塞的毫秒数;

    2、sleep存在异常InterruptedException;

    3、sleep时间达到后线程进入就绪状态;

    4、sleep可以模拟网络延时,倒计时等。

    5、每一个对象都有一个锁,sleep不会释放锁;

    package SunThread;

    //runnable实现买票过程

    //sleep放大问题的发生性

    public class Thread_04 implements Runnable{

    private int a=10;

    @Override

    public void run() {

    while(a>0){

    try {

    Thread.sleep(200);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(Thread.currentThread().getName()+"拿到了第"+a--+"张票");

    }

    }

    public static void main(String[] args) {

    Thread_04 thread_04 = new Thread_04();

    new Thread(thread_04,"小明").start();

    new Thread(thread_04,"小李").start();

    new Thread(thread_04,"小红").start();

    }

    }

    a223cd6ec078623aef90660dd606a9fd.png

    注:sleep放大问题的发生性,运用sleep可以编写倒计时、模拟网络延时等等。

    2.3线程的礼让(yield)

    1、礼让线程,让当前正在执行的线程暂停,但不阻塞;

    2、将线程从运行状态转为就绪状态;

    3、让CPU重新调度,礼让不一定成功!看CPU心情

    package SunThread;

    import javax.xml.transform.sax.SAXSource;

    public class ThreadYield_01 implements Runnable{

    @Override

    public void run() {

    System.out.println(Thread.currentThread().getName()+"该线程开始执行!");

    Thread.yield();

    System.out.println(Thread.currentThread().getName()+"该线程停止执行!");

    }

    public static void main(String[] args) {

    ThreadYield_01 threadYield_01 = new ThreadYield_01();

    new Thread(threadYield_01,"A").start();

    new Thread(threadYield_01,"B").start();

    }

    }

    77f64bb28b2be75a13f1d5d74f3e5fdf.png

    礼让不一定会成功

    2.4线程的强制执行(join)

    1、Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞

    2、可以想象成插队

    package SunThread;

    public class ThreadJoin_01 implements Runnable{

    @Override

    public void run() {

    try {

    Thread.sleep(200);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    for (int i = 0; i < 1000; i++) {

    System.out.println("线程vip来了"+i);

    }

    }

    public static void main(String[] args) throws InterruptedException {

    ThreadJoin_01 threadJoin_01 = new ThreadJoin_01();

    Thread thread = new Thread(threadJoin_01);

    thread.start();

    for (int i = 0; i < 1000; i++) {

    if(i==500)

    {

    thread.join();

    }

    System.out.println("main"+i);

    }

    }

    }

    c76c84a25893fd57acd6c4cbc14fbfd9.png

    由于现在CPU一般多核进行处理,我们可以在run()方法中设置一个休眠时间。

    3、线程的状态

    3.1运用代码的输出线程状态

    1、NEW 尚未启动的线程处于此状态。

    2、RUNAABLE 在Java虚拟机中执行的线程处于此状态。

    3、BLOCKED 被阻塞等待监视器锁定的线程处于此状态。

    4、WAITING 正在等待另一个线程执行特定动作的线程处于此状态。

    5、TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。

    6、TEPM4INATED 已退出的线程处于此状态。

    package SunThread;

    public class Thread_06 {

    public static void main(String[] args) throws InterruptedException {

    //运用lambda表达式对方法进行简化

    Thread thread=new Thread(()->{

    for (int i = 0; i < 5; i++) {

    try {

    Thread.sleep(200);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    System.out.println("==========");

    });

    //观察状态

    Thread.State state = thread.getState();

    System.out.println(state);//期待输出NEW

    //观察启动后

    thread.start();

    state = thread.getState();

    System.out.println(state);//RUN

    while(state!=thread.getState().TERMINATED)

    {

    thread.sleep(200);

    state = thread.getState();

    System.out.println(state);//RUN

    }

    }

    }

    f3c48c2195a23ff08d4a9fcc330cf2d4.png

    4、线程的优先级

    4.1设置优先级并输出

    Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。

    线程的优先级用数字表示,范围从1~10.

    Thread.MIN_PRIORITY= 1;

    Thread.MAX_PRIORITY= 10;

    Thread.MAX_PRIORITY= 10;

    getPriority() . setPriority(int xxx)

    优先级的设定建议在start()调度前

    package SunThread;

    public class ThreadPriority_01 {

    public static void main(String[] args) {

    //主线程优先级

    System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

    MyPriority myPriority = new MyPriority();

    Thread t1 = new Thread(myPriority);

    Thread t2 = new Thread(myPriority);

    Thread t3 = new Thread(myPriority);

    Thread t4 = new Thread(myPriority);

    Thread t5 = new Thread(myPriority);

    Thread t6 = new Thread(myPriority);

    t1.start();

    t2.setPriority(1);

    t2.start();

    t3.setPriority(4);

    t3.start();

    t4.setPriority(Thread.MAX_PRIORITY);//Thread.MAX_PRIORITY=10

    t4.start();

    t5.setPriority(8);

    t5.start();

    t6.setPriority(7);

    t6.start();

    }

    }

    class MyPriority implements Runnable{

    @Override

    public void run() {

    System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

    }

    }

    885bde23c11dee87e877131a72590f6e.png

    优先级低只是意味着获得调度的概率低.并不是优先级低就不会被调用了.这都是看CPU的调度

    优先级的设定建议在start()调度

    5、线程的守护

    5.1代码解释线程的守护

    1、线程分为用户线程和守护线程

    2、虚拟机必须确保用户线程执行完毕

    3、虚拟机不用等待守护线程执行完毕

    4、如,后台记录操作日志,监控内存,垃圾回收等待!.

    package SunThread;

    public class ThreadDaemon_01 {

    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("生活了"+i+"天");

    }

    System.out.println("goodbye world!");

    }

    }

    9752a13fe5dae50f0ace6557aa62c736.png

    6、线程的同步机制

    6.1线程的同步理解

    ​由于我们可以通过private 关键字来保证数据对象只能被方法访问﹐所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块.

    ​同步方法:public synchronized void method(int args)0{}

    ​synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行﹐否则线程会阻塞,方法一旦执行﹐就独占该锁,直到该方法返回才释放锁﹐后面被阻塞的线程才能获得这个锁,继续执行.

    ​缺陷:若将一个大的方法申明为synchronized将会影响效率

    6.2线程的不安全性

    用到lambda表达式简化https://blog.csdn.net/SUN__CGJ/article/details/109406652

    package SunThread;

    import java.util.ArrayList;

    public class Thread_07 {

    public static void main(String[] args) {

    ArrayList list = new ArrayList<>();

    for (int i = 0; i < 10000; i++) {

    //lambda表达式简化

    new Thread(()->{list.add(Thread.currentThread().getName())}).start();

    }

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(list.size());

    }

    }

    d83b4a158b42a90f78cf7ee3198047c7.png

    期待输出9999,但是输出只有9994,这就是线程的不安全性。

    6.3实现线程同步

    同步块 :synchronized (Obj ){}

    Obj称之为同步监视器

    Obj可以是任何对象﹐但是推荐使用共享资源作为同步监视器

    同步方法中无需指定同步监视器﹐因为同步方法的同步监视器就是this ,就是这个对象本身﹐或者是class [反射中讲解]

    同步监视器的执行过程

    1.第一个线程访问﹐锁定同步监视器﹐执行其中代码.

    2第二个线程访问﹐发现同步监视器被锁定﹐无法访问.

    3.第一个线程访问完毕﹐解锁同步监视器.

    4.第二个线程访问,发现同步监视器没有锁,然后锁定并访问

    package SunThread;

    import java.util.ArrayList;

    public class Thread_07 {

    public static void main(String[] args) {

    ArrayList list = new ArrayList<>();

    for (int i = 0; i < 10000; i++) {

    //lambda表达式简化

    new Thread(()->{

    synchronized (list){

    list.add(Thread.currentThread().getName());

    }

    }).start();

    }

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(list.size());

    }

    }

    ef9f43512ad83c81de4e2b97459968b0.png

    这样就是与我们的期待值相符合了。简单理解就是加锁,锁的是所需要操作的对象。

    补充:

    运用JUC并发编程实现同步。

    package SunThread;

    import java.util.concurrent.CopyOnWriteArrayList;

    public class Thread_08 {

    public static void main(String[] args) {

    CopyOnWriteArrayList list = new CopyOnWriteArrayList();

    for (int i = 0; i < 10000; i++) {

    new Thread(()->{

    list.add(Thread.currentThread().getName());

    }).start();

    }

    try {

    Thread.sleep(3000);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(list.size());

    }

    }

    9a11382dcc334d52a02cb3d27c9df616.png

    7、线程的死锁状态

    7.1死锁

    ​多个线程各自占有一些共享资源﹐并且互相等待其他线程占有的资源才能运行﹐而导致两个或者多个线程都在等待对方释放资源﹐都停止执行的情形.某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题.

    产生死锁的四个必要条件:

    1.互斥条件:一个资源每次只能被一个进程使用。

    2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

    3.不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

    4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

    用两个小孩想吃苹果和香蕉进行解释

    package SunThread;

    public class DeadLock_01 {

    public static void main(String[] args) {

    Eat e1 = new Eat(0, "小明");

    Eat e2 = new Eat(2, "小红");

    e1.start();

    e2.start();

    }

    }

    class Apple{ }

    class Banana{ }

    class Eat extends Thread{

    static Apple apple=new Apple();

    static Banana banana=new Banana();

    int choice;

    String name;

    Eat(int choice,String name){

    this.choice=choice;

    this.name=name;

    }

    @Override

    public void run() {

    try {

    eating();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    private void eating() throws InterruptedException {

    if(choice==0){

    synchronized (apple){

    System.out.println(this.name+"获得苹果的锁");

    Thread.sleep(1000);

    synchronized (banana){

    System.out.println(this.name+"获得香蕉的锁");

    }

    }

    }

    else{

    synchronized (banana){

    System.out.println(this.name+"获得香蕉的锁");

    Thread.sleep(2000);

    synchronized (apple){

    System.out.println(this.name+"获得苹果的锁");

    }

    }

    }

    }

    }

    d2b6067bd1a0e02b8ede0b3e14a6b6fb.png

    期待输出:

    小明获得苹果的锁

    小红获得香蕉的锁

    小明获得香蕉的锁

    小红获得苹果的锁

    但是输出的不一样,而且程序在一直运行。

    解决方法:

    package SunThread;

    public class DeadLock_01 {

    public static void main(String[] args) {

    Eat e1 = new Eat(0, "小明");

    Eat e2 = new Eat(2, "小红");

    e1.start();

    e2.start();

    }

    }

    class Apple{ }

    class Banana{ }

    class Eat extends Thread{

    static Apple apple=new Apple();

    static Banana banana=new Banana();

    int choice;

    String name;

    Eat(int choice,String name){

    this.choice=choice;

    this.name=name;

    }

    @Override

    public void run() {

    try {

    eating();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    private void eating() throws InterruptedException {

    if(choice==0){

    synchronized (apple){

    System.out.println(this.name+"获得苹果的锁");

    }

    Thread.sleep(1000);

    synchronized (banana){

    System.out.println(this.name+"获得香蕉的锁");

    }

    }

    else{

    synchronized (banana){

    System.out.println(this.name+"获得香蕉的锁");

    }

    Thread.sleep(2000);

    synchronized (apple){

    System.out.println(this.name+"获得苹果的锁");

    }

    }

    }

    }

    153ffda3579616be823ea1a79638c6d4.png

    7、Lock锁

    ​从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当

    ​java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

    ​ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

    ​买票的例子进行解释。

    package SunThread;

    import java.util.concurrent.locks.ReentrantLock;

    public class TeskLock_01 {

    public static void main(String[] args) {

    TeskLock teskLock = new TeskLock();

    new Thread(teskLock, "小明").start();

    new Thread(teskLock, "小李").start();

    new Thread(teskLock, "小红").start();

    }

    }

    class TeskLock implements Runnable {

    private int a = 10;

    //定义lock

    private final ReentrantLock lock = new ReentrantLock();

    @Override

    public void run() {

    while (true) {

    lock.lock();//加锁

    try {

    if(a>0) {

    Thread.sleep(200);

    System.out.println(Thread.currentThread().getName() + "拿到了第" + a-- + "张票");

    }

    } catch (InterruptedException e) {

    e.printStackTrace();

    } finally {

    lock.unlock();//解锁

    }

    }

    }

    }

    94a96829e4cf128e30f3919c7e83971a.png

    符合常理。

    8、生产者与消费者问题

    8.1应用场景:生产者消费者问题

    1、假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费.

    2、如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止.

    3、如果产品中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库再次放入产品为止.

    Java提供了几个方法解决线程之间的通信问题

    2ffaebf0abe7ee0fa97273c84e2a98b5.png

    8.2管程法进行实现

    生产者:负责生产数据的模块(可能是方法,对象,线程,进程)

    消费者:负责处理数据的模块(可能是方法,对象,线程,进程)

    缓冲区:消费者不能直接使用生产者的数据,他们之间有个缓冲区,生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据

    样例思路:

    1.首先有一个生产者,消费者、生产者只顾生产,消费者只管消费、

    2.利用了一个缓冲区,缓冲了一个10个大小的数组

    3.有个方法叫放入产品,产品丢进来的时候,我们判断一下缓冲区有没有满,如果满了的话,生产者就要等待了,

    如果没有满,就将产品放进去,放进去之后有产品了,赶紧通知消费者消费

    4.消费者就判断下能不能消费呢,有没有东西,有东西的话,我就可以直接消费,消费完了,就赶紧通知生产者生产。

    如果没有东西呢,消费者就等待。等待生产者去通知他,生产者通知了,他就可以解除等待了

    package SunThread;

    //测试: 生产者消费者模型-->利用缓冲区解决:管程法

    //生产者 , 消费者 , 产品 , 缓冲区

    public class TestPC {

    public static void main(String[] args) {

    SynContainer container = new SynContainer();

    new Productor(container).start();

    new Consumer(container).start();

    }

    }

    //生产者

    class Productor extends Thread {

    SynContainer container;

    public Productor(SynContainer container) {

    this.container = container;

    }

    //生产

    @Override

    public void run() {

    for (int i = 0; i < 100; i++) {

    container.push(new Chicken(i));

    System.out.println("生产了" + i + "只鸡");

    }

    }

    }

    //消费者

    class Consumer extends Thread {

    SynContainer container;

    public Consumer(SynContainer container) {

    this.container = container;

    }

    //消费

    @Override

    public void run() {

    for (int i = 0; i < 100; i++) {

    System.out.println("消费了-->" + container.pop().id + "只鸡");

    }

    }

    }

    //产品

    class Chicken {

    int id;//编号

    public Chicken(int id) {

    this.id = id;

    }

    }

    //缓冲区

    class SynContainer {

    //需要一个容器大小

    Chicken[] chickens = new Chicken[10];

    //容器计数器

    int count = 0;

    //生产者放入产品

    public synchronized void push(Chicken chicken) {

    //如果容器满了,就需要等待消费者消费

    if (count == chickens.length) {

    //生产者等待

    try {

    this.wait();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    //如果没有满,我们需要丢入产品

    chickens[count] = chicken;

    count++;

    //可以通知消费者消费了.

    this.notifyAll();

    }

    //消费者消费产品

    public synchronized Chicken pop() {

    //判断能否消费

    if (count == 0) {

    //消费者等待

    try {

    this.wait();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    //如果可以消费

    count--;

    Chicken chicken = chickens[count];

    //吃完了,通知生产者生产

    this.notifyAll();

    return chicken;

    }

    }

    c8b6286de50dfcc96a1ec376533fcef5.png

    8.3信号灯法

    ​来判断一个标志位flag,如果为true,就让他等待、如果为false,就让他去通知另外一个人、把两人衔接起来,就像咱们的信号灯红灯停,绿灯行,通过这样一个判断方式,只要来判断什么时候让他等待,什么时候将他唤醒就ok。

    package SunThread;

    //测试生产者消费者问题2:信号灯法,通过标志位解决

    public class TestPC_01 {

    public static void main(String[] args) {

    TV tv = new TV();

    new Player(tv).start();

    new Watcher(tv).start();

    }

    }

    //生产者-->演员

    class Player extends Thread {

    TV tv;

    public Player(TV tv) {

    this.tv = tv;

    }

    @Override

    public void run() {

    for (int i = 0; i < 20; i++) {

    if (i % 2 == 0) {

    this.tv.play("快乐大本营播放中");

    } else {

    this.tv.play("抖音:记录美好生活");

    }

    }

    }

    }

    //消费者-->观众

    class Watcher extends Thread {

    TV tv;

    public Watcher(TV tv) {

    this.tv = tv;

    }

    @Override

    public void run() {

    for (int i = 0; i < 20; i++) {

    tv.watch();

    }

    }

    }

    //产品-->节目

    class TV {

    //演员表演,观众等待 T

    //观众观看,演员等待 F

    String voice; // 表演的节目

    boolean flag = true;

    //表演

    public synchronized void play(String voice) {

    if (!flag) {

    try {

    this.wait();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    System.out.println("演员表演了:" + voice);

    //通知观众观看

    this.notifyAll();

    this.voice = voice;

    this.flag = !this.flag;

    }

    //观看

    public synchronized void watch() {

    if (flag) {

    try {

    this.wait();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    }

    System.out.println("观看了:" + voice);

    //通知演员表演

    this.notifyAll();

    this.flag = !this.flag;

    }

    }

    f707f1d10df3c4b6a0b482a4021e5027.png

    9、线程池

    9.1用Runable实现线程池

    背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大

    思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中公共交通工具。

    好处:

    提高响应速度(减少了创建线程的时间)

    降低资源的消耗(重复利用线程池中线程,不需要每次都创建)

    便于线程管理(...)

    corePoolSize:核心池的大小

    maximumPoolSize:最大线程数

    keepAliveTime:线程没有任务时最多保持多长时间后会终止

    JDK 5.0起提供了线程池相关API:ExecutorService 和 Executors

    ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor

    void execute(Runnable command):执行任务/命令,没有返回值,一 般用来执行Runnable

    Futuresubmit(Callabletask):执行任务,有返回值,一般用来执行Callable

    void shutdown():关闭连接池

    6.Executors:工具类、线程池的工厂类、用于创建并返回不同类型的线程池

    用Runable实现线程池

    package SunThread;

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

    //测试线程池

    public class TestPool {

    public static void main(String[] args) {

    //1.创建服务,创建线程池

    //newFixedThreadPool(10); 参数为线程池的大小

    ExecutorService service = Executors.newFixedThreadPool(10);

    //执行

    service.execute(new MyThread());

    service.execute(new MyThread());

    service.execute(new MyThread());

    service.execute(new MyThread());

    //2.关闭连接

    service.shutdown();

    }

    }

    class MyThread implements Runnable {

    @Override

    public void run() {

    System.out.println(Thread.currentThread().getName());

    }

    }

    ad435ee7809fc035ba7d8c4992b4b24e.png

    自学习于哔哩哔哩狂神说JAVA(侵删);

    作为自己的笔记,欢迎大家斧正!

    展开全文
  • 一、线程、进程、多线程1、线程与进程定义进程:进程是系统进行资源分配和调度的基本单位,是操作系统中一个运行的程序,是线程的容器;线程:线程是处理机调度的最小单位,包含在进程中,是进程中实际运作单位;一...
  • Java多线程

    2021-02-28 06:03:31
    多线程应用程序的执行都是cpu在做着快速的切换完成的。这个切换是随机的1、进程直译:正在进行中的程序一个程序就是一个进程,而一个程序中的多个任务则被称为线程,进程其实就是一个静态的概念2、线程(控制单元/...
  • Day13 多线程3).多线程的好处:提高程序的运行效率,提高用户的体验度。 线程不会因为等待某个资源而进入等待状态创建新的线程:* 定义类继承Thread* 重写方法run* 创建Thread子类的对象* 调用子类对象的方法start()*...
  • python中使用多线程处理程序,会比一步步的处理节约很多时间,而且通过创建并继承Python的Thread类,重写run()方法,通过自定义的线程类来创建线程,本文介绍python多线程Thread类定义和如何自定义线程类的过程。...
  • 最近在研究Spring Boot中的异步处理,发现涉及到异步和多线程的很多知识点,就先写几篇关于异步与多线程的文章,带大一起回顾或学习一下相关的知识点。下面开始正文内容: 前言 在本文中,我们通过一些通俗易懂的...
  • JAVA 线程定义

    千次阅读 2021-06-14 23:32:55
    基本概念: 并发与并行 并行:指两个或个事件在同一时刻发生(同时发生)。 并发:指两个或个事件在同一个时间段内发生。
  • import android.app.Activity; import android.os.Bundle;...在程序中我们使用线程时因为它处理比较耗时的操作,Activity也不能等着处理(如果放在主程序中则会显示程序长时间无响应,会被关闭),用的时候要注意。
  • 首先说下多线程出现的原因: 为了解决负载均衡问题,充分利用CPU资源.为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰.为了处理大量的IO操作时或处理的情况需要花费大量的时间等等,比如:读写...
  • 多进程还是多线程

    2021-03-10 04:24:50
    就像莎士比亚的“To be, or not to be, that is thequestion”始终困扰着哈姆雷特,对于“进程还是线程?...由于这个问题很容易引发口水战,事先声明如下:多进程和多线程,无法一概而论地说谁比谁好。因...
  • 多线程带来的问题 为什么需要多线程 其实说白了,时代变了,现在的机器都是多核的了,为了榨干机器最后的性能我们引入单线程。 为了充分利用CPU资源,为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不...
  • 1 为什么要用Runnable上一篇...为了避免这种局限性,所以又提供了第二种多线程主体定义的形式:实现Runnable接口。2 创建一个实现Runnable的对象我们先创建一个RunnableDemo类,并在里面创建一个MyThread2内部类,...
  • 一直想写一个多线程博客,汇总一下方老师教给我们的知识。但是因为一直没有用到,或者自己还没有吃透里面的精髓,所以不敢下笔。现在工作中又遇到必须要通过多线程解决的问题,所以再回顾以前方老师的课程,从头整理...
  • Java多线程整理

    2021-03-01 06:23:38
    一、线程池过于频繁的创建/销毁线程浪费性能,线程并发数量过多,JVM调度是抢占式的,线程上线文切换抢占系统资源导致阻塞。1.线程池线程数:一般CPU密集型:CPU+1IO密集型:[(线程等待时间+线程CPU时间)/线程CPU...
  • Linux C中多线程与volatile变量volatile 修饰的变量表示改变量的值是易变的,编译器不对其进行优化,访问该变量的时候不会从寄存器读取, 而是直接从内存读取变量。在多线程环境下,每个线程都有一个独立的寄存器,...
  • 多线程和多进程通常在硬件层面上和操作系统层面上都存在线程的概念。但是这两个概念是完全不同的,是一个词汇在不同层面上的不同意思。CPU数,核心数,硬件的线程数CPU数指的是一个计算机主板上实际上卡槽中插入的...
  • 上面博客中,我们的最大线程数量是自定义,但是通常情况下,我们并不会这么做。 1.解决办法 CPU密集型 IO密集型 2.什么是CPU密集型? 比如让你(CPU)数一堆豆子(要执行的任务),在数的过程中,不就不能去干别的...
  • 在这篇文章里,我们首先阐述什么是同步,不同步有什么问题,然后...说到线程同步,大部分情况下, 我们是在针对“单对象多线程”的情况进行讨论,一般会将其分成两部分,一部分是关于“共享变量”,一部分关于“执行...
  • 2006 年 8 月 14 日Java 提供了语言级别的线程支持,所以在 Java 中使用多线程相对于 C,C++ 来说更简单便捷,但本文并不是介绍如何在 Java 中使用多线程来来解决诸如 Web services, Number crunching 或者 I/O ...
  • Java 多线程(超详细)

    千次阅读 2021-01-12 21:14:38
    多线程学习思路:为什么学习线程?为了解决CPU利用率问题,提高CPU利用率。 =》 什么是进程?什么是线程? =》 怎么创建线程?有哪几种方式?有什么特点? =》 分别怎么启动线程? =》 多线程带来了数据安全问题,该...
  • 虽然可以通过Thread类的继承来实现多线程定义,但是在Java程序里面对于继承永远是存在单继承局限的,所以在Java里面又提供有第二种多线程的主体定义结构形式,实现java.lang.Runnable接口,此接口定义如下: ...
  • Java多线程(一文看懂!)

    2021-07-28 17:36:15
    一,多线程的介绍 二,多线程的实现方式 三,多线程的五大状态 四,多线程的调度 五,线程的同步(多口售票问题) 六,线程的协作(生产者-消费者模型) 一,多线程的介绍 百度中多线程的介绍(multithreading):...
  • Spring Boot 多线程使用

    2021-01-05 19:09:58
    Spring Boot 提供了非常优雅使用多线程执行任务的方式,本文说明 Spring Boot 项目如何利用 ThreadPoolTaskExecutor 来使用多线程。 创建 Spring Boot 项目 使用 IntelliJ Idea 创建向导创建一个 Spring Boot 项目,...
  • Selenium+Python多线程

    千次阅读 2021-01-14 05:18:38
    Python通过两个标准库thread和threading提供对线程的支持。我们应避免使用thread模块,原因是它不支持线程守护(即当主线程退出时,所有的子线程不管它们还在工作与否,都会被强行退出)。from threading import ...
  • 多线程-线程的创建

    2020-12-21 21:38:10
    线程的创建方式总结一下多线程的创建方式,多线程的实现一共四种方法,接下来将详谈一下创建的方式1、继承Thread类,而后覆写run()方法2、实现Runnable接口,而后覆写run()方法3、实现callable接口,而后覆写call...
  • C++ 多线程文件写入

    2021-05-04 10:24:07
    C++ 多线程文件写入 文件IO操作 CreateFile WriteFile 多线程创建 CreateThread 线程控制 CRITICAL_SECTION临界区资源控制,WaitForMultipleObjects多线程等待返回 // ThreadWrite.cpp : 定义控制台应用程序...
  • 多线程抢票详解

    2021-03-13 21:36:14
    功能实现:多线程模拟售票系统定义一个车票类,车票类拥有票号属性、 车票状态(未售、售出)属性和拥有者(String类型)属性;在主线程中定义一个票库(ArrayList数组列表)初始化票库并生产200张票;定义一个乘客类继承...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 999,346
精华内容 399,738
关键字:

多线程的定义