zoukankan      html  css  js  c++  java
  • 线程的基本方法



    1. 进程与线程

    进程:资源分配的基本单位

    线程:资源调度的基本单位


    1.1 有了进程为什么还需要线程呢?

    为了进程能进行并发操作


    1.2 线程的生命周期



    2. 创建进程

    创建进程有两种方法(一般推荐第二种,因为单继承问题)


    先来看看线程的构造函数


    2.1 继承Thread类,重写run()

    public class Threadtest extends Thread {
        
        //设置名字
    	public Threadtest(String name) {
    		super(name);
    	}
    	
    	//重写方法
    	public void run(){
    		for(int i = 0;i < 100;i++){
    			System.out.println(Thread.currentThread().getName() + "-----" + i);
    		}
    	}
    	
    	public static void main(String[] args) {
    		
    		Threadtest t1 = new Threadtest("线程1");
    		Threadtest t2 = new Threadtest("线程2");
    		
    		t1.start();
    		t2.start();
    	}
    }
    

    2.2 实现Runnable接口,重写run()

    public class Runnabletest implements Runnable {
    	
    	@Override
    	public void run() {
    		for(int i = 0;i < 100;i++){
    			System.out.println(Thread.currentThread().getName() + ":::" + i);
    		}
    	}
    	
    	public static void main(String[] args) {
    		
    		Thread t1 = new Thread(new Runnabletest(),"线程1");
    		Thread t2 = new Thread(new Runnabletest(),"线程2");
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    // 上面两种方法都是线程交替进行
    线程1:::0
    线程1:::1
    线程1:::2
    线程1:::3
    线程1:::4
    线程2:::0
    线程1:::5
    线程1:::6
    线程1:::7
    线程1:::8
    线程1:::9
    线程1:::10
    线程2:::1
    


    3.线程的方法


    3.1 命名 getName()

    • 该构造函数里的init方法的第三个参数是线程名
    • 第三个参数是个函数,该函数同步地维护了threadInitNumber,是一个数字
    • 可想而知,线程名字是 Thread-Number,eg: Thread-0
    • 从2.1/2.2可知构造方法里面提供了命名线程的方式
    /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     */
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    
    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }
    
    • 也可以通过 setName(String name) 来命名,不过该方法调用native方法,笔者水平有限不做深究
    Thread thread = new Thread(() -> {
        System.out.println(Thread.currentThread().getName());
    });
    thread.setName("新线程名");
    
    新线程名
    

    3.1 守护线程(setDaemon)

    • 守护进程是为其他线程服务的线程,存在于后台,一旦有线程就存在,线程全部消失而结束,eg: 垃圾回收线程
    • 守护线程中产生的新线程也是守护线程
    • 需要在进程启动前调用Thread.setDaemon(true),会用native方法检测,非法则抛出异常
    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;	//设置守护线程为真
    }
    
    /* Whether or not the thread is a daemon thread. */
    // private boolean  daemon = false;
    

    3.2 优先级(setPriority)

    • 设置获取CPU时间片的几率,分0—10等级,默认为5
    // MAX_PRIORITY 最大级别10
    // MIN_PRIORITY 最小0
    // NORM_PRIORITY 普通5
    
    public final void setPriority(int newPriority) {
    	ThreadGroup g;  //线程组
    	checkAccess();
    	if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);  //设置级别,后面遇到native方法不说明了
        }
    }
    
    public static void main(String[] args) {
    		
    		Threadtest t1 = new Threadtest("线程1");
    		Threadtest t2 = new Threadtest("线程2");
        
        	//设置优先级
        	t1.setPriority(10);
    		
    		t1.start();
    		t2.start();
    }
    
    线程1:::97
    线程1:::98
    线程1:::99
    线程2:::3
    线程2:::4
    线程2:::5
    

    在前面实例中调用该函数,发现t1线程cpu执行时间片多于t2线程,t1完成了t2还在开头


    3.3 sleep

    • 让该线程休眠,不释放锁

    • 结束重回就绪状态

    • t1.sleep(),不是t1睡眠,而是当前线程睡眠

    • 哪个线程调用sleep方法,哪个线程就睡眠

    public class Threadtest extends Thread {
    	
    	//设置名字
    	public Threadtest(String name) {
    		super(name);
    	}
    
    	//重写方法
    	public void run(){
    		for(int i=0; i < 100;i++){
    			System.out.println(Thread.currentThread().getName() + "--" + i);
    		}
    		
    	}
    	
    	public static void main(String[] args) throws InterruptedException {
    		Threadtest t2 = new Threadtest("线程2");
    
    		t2.start();
    		t2.sleep(10000);
    		
    		System.out.println("=========");
    	}
    }
    
    线程2--96
    线程2--97
    线程2--98
    线程2--99
    //10秒后,main线程睡眠
    =======
    

    3.4 join

    • 使当前线程停下来等待,直到调用join()的线程结束,才恢复执行
    • 它可以使得线程之间的并行执行变为串行执行
    • 在start之后才执行的
    • 底层还是调用wait方法
    public class Threadtest extends Thread {
    	
    	//设置名字
    	public Threadtest(String name) {
    		super(name);
    	}
    
    	//重写方法
    	public void run(){
    		for(int i=0; i < 100;i++){
    			System.out.println(Thread.currentThread().getName() + "--" + i);
    		}
    		
    	}
    	
    	public static void main(String[] args) throws InterruptedException {
    		
    		Threadtest t1 = new Threadtest("线程1");
    		Threadtest t2 = new Threadtest("线程2");
    
    		t2.setPriority(10);
    		t1.start();
    		t1.join();		//main线程停下来,等t1执行完才继续往下执行,所以先输入t1,再输出t2
    		t2.start();
    	}
    }
    

    3.5 wait和notify

    • wait使当前线程挂起,notify随机唤醒一个同享对象锁的线程,notifyAll唤醒所有
    • wait必须在同步代码块或同步方法中调用,先要有锁才能释放锁
    • wait方法释放锁,并处于阻塞状态
    • notify不是立即释放锁,要执行完同步操作才释放锁
    • 被其他线程唤醒后处于就绪状态
    thread.wait();
    thread.notify();
    

    3.6 yield

    使当前线程从运行状态转为就绪状态,即可能让别的线程执行,也可能自己再次执行


    3.7 interrupt

    • 该方法不是即时中断线程,而是仅仅设置一个中断信号量,然后中断操作由我们自己实现
    Thread t1 = new Thread(new Runnable(()->{
        // 若未发生中断,就正常执行任务
        while(!Thread.currentThread.isInterrupted()){
            // 正常任务代码……
        }
        // 中断的处理代码……
        doSomething();
    }).start();
    
    • 当线程在活动之前或活动期间处于阻塞状态(正在等待、休眠或占用状态)且该线程被中断时,抛出InterruptedException
    • 阻塞线程调用interrupt()方法,会抛出异常,设置标志位为false,同时该线程会退出阻塞

    #### 3.8 exit

    退出当前线程(或者当run方法结束也是线程结束)


    3.9 start和run区别

    • run():仅仅是封装被线程执行的代码,直接调用是普通方法

    • start():创建线程,jvm调用线程的run()方法,所以start方法执行完,不代表run方法执行完,线程也不一定销毁!


    3.10 currentThread()

    获取当先运行的线程,Thread thread = Thread.currentThread(),属于静态方法



  • 相关阅读:
    【jQuery Case Study 1】Site:cssninjas.com
    PostgreSQL HA双机热备份配置
    PogreSQL物理备份与逻辑备份
    转:truncate,delete和drop删除表的异同
    pgsequence序列的用例
    Linux下端口占用的解决方法
    Linux下脚本的编写和执行
    schema模式的选用
    pg数据库基础备份的注意事项
    PostgreSQL VMCC多版本并发控制
  • 原文地址:https://www.cnblogs.com/Howlet/p/12015259.html
Copyright © 2011-2022 走看看