• 并发编程--多线程基础(01)


    1.关于多线程

    1.1 线程与进程的区别

    进程:系统中每一个正在运行的程序都是一个进程,每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元

    线程:是一组指令的集合,控制着进程的执行,一个进程中至少有一个线程

    1.2 为什么用多线程

    使用多线程可以将执行时间长的程序中的任务放到后台去处理,在一些需要等待的任务上如文件读写、网络分发数据等,使用多线程就可以更好的利用CPU的资源,从而提高程序运行的效率

    2. 线程的状态

    线程有5种状态:新建、就绪、运行、阻塞、死亡,如下图所示:

    新建状态:当new一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码

    就绪状态:一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由java运行时系统的线程调度程序(thread scheduler)来调度的。

    运行状态:当线程竞争到CPU时间之后,执行run()方法,进入运行状态

    阻塞状态:线程运行过程中,可能由于各种原因进入阻塞状态:

    1)线程通过调用sleep方法进入睡眠状态;

    2)线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;

    3)线程试图得到一个锁,而该锁正被其他线程持有;

    4)线程在等待某个触发条件;

    所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

    死亡状态:有两种原因会导致线程进入死亡状态:

    1)run()方法执行完成正常死亡

    2)发生异常终止了run()方法而进入死亡状态

    3. 创建线程的方法

    3.1 继承Thread类,重写run()方法

    class CreateThread extends Thread {
    	
    	publicvoid run() {
    		// run方法中编写 多线程需要执行的代码
    	}
    }
    

    3.2 实现Runnable接口,重写run()方法

    class CreateRunnable implements Runnable {
    
    	@Override
    	publicvoid run() {
    		//run方法中编写多线程需要执行的代码
    	}
    
    }
    

    3.3 匿名内部类方式

    Thread thread = new Thread(new Runnable() {
    			public void run() {
    				//run方法中编写多线程需要执行的代码
    			}
    });
    

    4. 常用的方法

    4.1 join()

    join():当线程B执行到了线程A的.join()方法时,B线程就会等待,等A线程都执行完毕,B线程才会执行,join可以用来临时加入线程执行。

    public class Thread002 {
    
    	public static void main(String[] args) {
    		Thread t1 = new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				for (int i = 0; i < 10; i++) {
    					System.out.print("这个是t1线程:" + i +"	");
    				}
    				System.out.println("
    --------------分割线------------------");
    			}
    		});
    
    		Thread t2 = new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				try {
    					t1.join();
    					
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				for (int i = 0; i < 10; i++) {
    					System.out.print("这个是t2线程:" + i+ "	");
    				}
    				System.out.println("
    --------------分割线------------------");
    			}
    		});
    
    		Thread t3 = new Thread(new Runnable() {
    
    			@Override
    			public void run() {
    				try {
    					t2.join();
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    				for (int i = 0; i < 10; i++) {
    					System.out.print("这个是t3线程:" + i +"	");
    				}
    				
    			}
    		});
    		t1.start();
    		t2.start();
    		t3.start();
    
    	}
    
    }
    

    4.2 sleep()、yield()

    sleep():让正在执行的线程休眠,因为使用sleep方法之后,线程是进入阻塞状态的,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒

    public class SynTest {
        public static void main(String[] args) {
            new Thread(new CountDown(),"倒计时").start();
        }
    }
    
    class CountDown implements Runnable{
        int time = 10;
        public void run() {
            while (true) {
                if(time>=0){
                    System.out.println(Thread.currentThread().getName() + ":" + time--);
                    try {
                        Thread.sleep(1000);                                                    //睡眠时间为1秒
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    yield():和sleep方法类似,也是Thread类提供的一个静态方法,可以让正在执行的线程暂停,但是不会进入阻塞状态,而是直接进入就绪状态。相当于只是将当前线程暂停一下,然后重新进入就绪的线程池中,让线程调度器重新调度一次。也会出现某个线程调用yield方法后暂停,但之后调度器又将其调度出来重新进入到运行状态

    public class SynTest {
        public static void main(String[] args) {
            yieldDemo ms = new yieldDemo();
            Thread t1 = new Thread(ms,"张三吃完还剩");
            Thread t2 = new Thread(ms,"李四吃完还剩");
            Thread t3 = new Thread(ms,"王五吃完还剩");
            t1.start();
            t2.start();
            t3.start();
        }
    }
    class yieldDemo implements Runnable{
        int count = 20;
        public void run() {
            while (true) {
                    if(count>0){
                        System.out.println(Thread.currentThread().getName() + count-- + "个瓜");
                        if(count % 2 == 0){
                            Thread.yield();                  //线程让步
                        }
                }
            }
        }
    }
  • 相关阅读:
    React实现新闻网站--使用动态路由获取不同列表内容
    Bootstrap4 轮播+模态框+提示框+弹出框
    JDK 升级问题小结
    JDK8 指南(译)
    如何学习一门编程语言
    redis 系列5 数据结构之字典(上)
    sql server 临时表(上) Tempdb概述
    redis 系列4 数据结构之链表
    redis 系列3 数据结构之简单动态字符串 SDS
    redis 系列2 知识点概述
  • 原文地址:https://www.cnblogs.com/Cryptonym/p/10668764.html
Copyright © 2020-2023  润新知