文章目录

  • 一、线程和进程
  • 二、线程的生命周期
  • 三、创建线程的三种方式
  • 1.继承Thread类
  • 2.实现Runnable接口
  • 3.实现Callable接口
  • 四、创建线程对象的3种方法
  • 五、线程控制阻塞的几种方式
  • sleep()方法
  • join()方法
  • yield()方法
  • 守护线程


一、线程和进程

什么是JUC? java.util.concurrent 也就是java工具类,在并发编程中用到

java线程是对象吗 线程是java的什么机制_java线程是对象吗

进程:进程是程序一个动态执行的过程。进程是操作系统资源分配的最小单位。进程之间相互独立。一个进程由一个或多个线程组成.

线程: 线程是进程执行的最小调度单位。多个线程共享一个进程下的资源,且一个进程下线程相互影响。一个进程内的线程在其他进程内是不可见;

Java默认有两个线程: 主(mian)线程、GC线程

进程的一些特性:

java线程是对象吗 线程是java的什么机制_java_02

线程和进程的比较:

java线程是对象吗 线程是java的什么机制_开发语言_03


java能否能开启线程?

不能,线程是由操作系统实现的,而java是运行在虚拟机之上的,无法直接操作硬件。java开启线程是通过底层调用了本地的C++方法。

//Thread底层的几个主要方法
    private static native void registerNatives();    
    public static native Thread currentThread();
    public static native void yield();   
    public static native void sleep(long millis) throws InterruptedException;
    public final native boolean isAlive();

Thread底层的相关方法都是被 native 关键字所修饰的。
在 Java 的 API 中,一个 native 方法往往意味着这个方法无法使用平台无关的手段来实现。
所以,线程的实现与 Java 无关,由平台所决定,Java 所做的是将 Thread 对象映射到操作系统所提供的线程上面去,对外提供统一的操作接口
这也是 Java 这门语言诞生之初的核心思想,一处编译,到处运行,只面向虚拟机,实现所谓的平台无关性,而这个平台无关性就是由虚拟机为我们提供的。

查看线程底层实现:

new Thread().start();

点开start()方法

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

首先。start()是一个synchronized方法,同步方法,安全,这个方法会把当前线程加入一个线程组,调用了start0()方法,这个start0(),是用native修饰的,也就是本地方法。所以最后是调用了本地方法,java是没有权限开启线程的。start()调用了本地的C++方法,因为java是运行在虚拟机之上的,无法直接操作硬件。

并发、并行
并发: cpu只有一个核:多线程操作同一个资源(cpu通过线程间的快速交替,模拟出来多条线程,看似并行,实际串行)
并行: 多个人一起行走,cpu有多个核,多个线程可以同时执行,可以通过线程池完成
并发编程的本质: 充分利用CPU的资源

二、线程的生命周期

Thread.State

点进State可以看到线程的生命周期

public enum State {
// 新生
NEW,
// 运行
RUNNABLE,
// 阻塞
BLOCKED,
// 等待,死死地等
WAITING,
// 超时等待
TIMED_WAITING,
// 终止
TERMINATED;
}

java线程是对象吗 线程是java的什么机制_后端_04

三、创建线程的三种方式

1.继承Thread类

创建线程的第一种方法。继承java.lang包的Thread类。

Thread类也是通过Runnable接口来创建线程对象。本质上Thread是Runnable的一个包装类。

java线程是对象吗 线程是java的什么机制_开发语言_05

java线程是对象吗 线程是java的什么机制_创建线程_06

package com.wdy.thread;
/*
 * 创建线程的第一种方法。继承java.lang包的Thread类
 * 
 */
public class ThreadDemo01 extends Thread {  //继承了Thread类。产生的对象是线程对象
    private String name;//线程名称
	   
	public ThreadDemo01(String name) {
		this.name=name;
	}
	
	@Override
    public void run() {  //覆盖run方法
    	for(int i=1;i<=10;i++) {
    		System.out.println(this.name+"-"+i);
    		try {
				sleep(200);  //线程阻塞
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
		
	public static void main(String[] args) {
		Thread t1=new ThreadDemo01("A"); //创建3个线程对象
		Thread t2=new ThreadDemo01("B");
		Thread t3=new ThreadDemo01("C");
		
		t1.start(); //线程对象就绪
		t2.start();
		t3.start();	
	}
}

执行结果:从结果可以看出多个线程是交错执行的。

java线程是对象吗 线程是java的什么机制_后端_07

2.实现Runnable接口

因为java是单继承,继承了Thread类,就不能继承其它类。所以第二种方法用Runnable接口来实现,在实现Runnable接口的同时还能继承一个类,在实际项目中运用较多。

package com.wdy.thread;
	/*
	 * 创建线程的第二种方法。实现Runnable接口
	 * 和方法一不同的地方在于阻塞 和创建线程对象
	 * 
	 */
	public class ThreadDemo02 implements Runnable {  //继承了Thread类。产生的对象是线程对象
	    private String name;//线程名称
			    
		public ThreadDemo02(String name) {
			this.name=name;
		}
		
		@Override
	    public void run() {  //覆盖run方法
	    	for(int i=1;i<=10;i++) {
	    		System.out.println(this.name+"-"+i);
	    		try {
					Thread.sleep(200); //阻塞
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    	}
	    }
				
		public static void main(String[] args) {
			Thread t1=new Thread(new ThreadDemo02("A")); // 创建3个线程对象 Thread.Runnable()方法
			Thread t2=new Thread(new ThreadDemo02("B")); // 创建3个线程对象
			Thread t3=new Thread(new ThreadDemo02("C")); // 创建3个线程对象
				
			t1.start(); //线程对象就绪
			t2.start();
			t3.start();		
		}	
}

执行结果:

java线程是对象吗 线程是java的什么机制_java线程是对象吗_08

3.实现Callable接口

唯一一种有返回值的。

在第三种方法。通过Callable接口创建线程对象使用的也是Runnable接口的实现类FutureTask()。

java线程是对象吗 线程是java的什么机制_java_09

package com.wdy.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadDemo03 implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
        int s=0;
        for(int i=1;i<=10000;i++) {
        	s+=i;
        }
		return s;
	}
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<Integer> ft=new FutureTask<Integer>(new ThreadDemo03());
	    ft.run();
	    System.out.println("结果为:"+ft.get());
	}
}

执行结果:

java线程是对象吗 线程是java的什么机制_java_10

四、创建线程对象的3种方法

  • 通过类来创建线程对象
  • 通过匿名内部类
  • 通过函数式编程
    Runnable接口实现了FunctionalInterface接口(函数接口)
package com.wdy.thread;
	public class ThreadDemo02 implements Runnable {  //继承了Thread类。产生的对象是线程对象
	    private String name;//线程名称
		
	    
		public ThreadDemo02(String name) {
			this.name=name;
		}
		
		@Override
	    public void run() {  //覆盖run方法
	    	for(int i=1;i<=10;i++) {
	    		System.out.println(this.name+"-"+i);
	    		try {
					Thread.sleep(200); //阻塞
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	    	}
	    }
		
	     /*第一种 通过类创建线程*/	
		public static void main(String[] args) {
//			Thread t1=new Thread(new ThreadDemo02("A")); // 创建3个线程对象 Thread.Runnable()方法
//			Thread t2=new Thread(new ThreadDemo02("B")); // 创建3个线程对象
//			Thread t3=new Thread(new ThreadDemo02("C")); // 创建3个线程对象
//				
//			t1.start(); //线程对象就绪
//			t2.start();
//			t3.start();		
//		
		
		 /*第二种 通过匿名内部类创建线程*/	
		 new Thread(new Runnable() {
			
			@Override
			public void run() {
				for(int i=1;i<=10;i++) {
		    		System.out.println(Thread.currentThread().getName()+"-"+i);
		    		try {
						Thread.sleep(200); //阻塞
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
		    	}
				
			}
		});
		
//		/*第三种 通过函数式接口创建线程*/	
//			new Thread(()->{
//				
//				for(int i=1;i<=10;i++) {
//		    		System.out.println(Thread.currentThread().getName()+"-"+i);
//		    		try {
//						Thread.sleep(200); //阻塞
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
//		    	}
//						
//			}).start();;	
		}
}

五、线程控制阻塞的几种方式

sleep()方法

sleep()实现线程阻塞的方法,我们称之为“线程睡眠”,方式是超时等待,就是sleep()通过传入“睡眠时间”作为方法的参数,时间一到就从“睡眠”中“醒来”;

join()方法

在t1.start()之后,对t1线程实现join() ,阻塞其它线程,控制t1线程优先执行完毕。

package com.wdy.thread;

public class ThreadBlockDemo01 extends Thread{
    private String name;//线程名称
	
	public ThreadBlockDemo01(String name) {
		this.name=name;
	}
	
	public void run() {  //覆盖run方法
    	for(int i=1;i<=10;i++) {
    		System.out.println(this.name+":"+i);
    		try {
				sleep(200); //阻塞
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
	
	public static void main(String[] args) throws InterruptedException {
		Thread t1=new Thread(new ThreadDemo02("A")); // 创建3个线程对象 Thread.Runnable()方法
		Thread t2=new Thread(new ThreadDemo02("B")); // 创建3个线程对象
		Thread t3=new Thread(new ThreadDemo02("C")); // 创建3个线程对象
			
		t1.start(); //线程对象就绪
		t1.join();  //阻塞线程A,让A线程优先执行
		t2.start();
//		t2.join();//阻塞线程B,让B线程优先执行
		t3.start();	
		
}
}

java线程是对象吗 线程是java的什么机制_后端_11

同理,在t2.start()之后,再加一个join() ,控制t2线程优先执行。执行结果如下:

java线程是对象吗 线程是java的什么机制_创建线程_12

yield()方法
package com.wdy.thread;

public class ThreadBlockDemo3 extends Thread{
    private String name;//线程名称
	
	public ThreadBlockDemo3(String name) {
		this.name=name;
	}
	
	public void run() {  //覆盖run方法
    	for(int i=1;i<=10;i++) {
    		if(i%2==0) {//当前线程为偶数,暂时让出cpu运行时间片
    			Thread.yield();
    		}
    		System.out.println(this.name+":"+i);
    		try {
				sleep(200); //阻塞
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }	

	public static void main(String[] args) throws InterruptedException {
		Thread t1=new Thread(new ThreadDemo02("A")); // 创建3个线程对象 Thread.Runnable()方法
		Thread t2=new Thread(new ThreadDemo02("B")); // 创建3个线程对象
		Thread t3=new Thread(new ThreadDemo02("C")); // 创建3个线程对象
			
		t1.start(); //线程对象就绪	
		t2.start();
		t3.start();		
}
}
守护线程
package com.wdy.thread;

public class Demo2 extends Thread {
    @Override
    public void run() {
    	while(true) {
    		System.out.println("线程运行中");
    		try {
				sleep(200);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    	}
    }
        
    public static void main(String[] args) throws InterruptedException {
		Thread t=new Demo2();//主线程
		t.setDaemon(true);//守护线程:主线程结束,其它线程也结束
		t.start();
		
    	for(int i=0;i<10;i++) { 
			System.out.println(i);
			Thread.sleep(200);
		}
	}
}

不加守护线程,会陷入死循环。结果如下

java线程是对象吗 线程是java的什么机制_java_13

加入守护线程的运行结果如下

t.setDaemon(true);主线程终止之后,其余线程也会被终止。

java线程是对象吗 线程是java的什么机制_java线程是对象吗_14