蒟蒻变大佬必学之Java多线程基本实现方法(Thread类和Runnable接口)

引言:

作为最早引入多线程机制的编程语言,Java对多线程的支持度非常高,虚拟机机制以及各类高并发框架,对高并发数据的保护,使得Java的多线程相对于C++等语言更加方便,这也是Java依然活跃在服务器上的重要原因之一。接下来,本文讲简单介绍使用Java多线程的基本流程。

先来简单回顾一下多线程、并发和并行的概念:
1·多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
2·并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。 3·并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。
具体的分析可以移步至上一篇文章:
浅谈线程,进程,多任务,多线程,多进程

Java中主要提供两种方式,分别继承java.lang.Thread类与实现java.lang.Runnable接口。

1)继承Thread类

Thread类是java.lang包中的一个类,从该类中实例化的对象表示线程,创建新线程时需要建立Thread实例,Thread中常用的两个构造方法如下:

public Thread() : //创建一个新的线程对象。
public Thread(String ThreadName) : //创建一个名称为ThreadName的线程对象

实现线程真正功能的代码需要放在类的run()方法中,当一个类继承Thread后,就可以在该类中覆盖run()方法,讲功能代码写在run()方法中,随后调用Thread类中的start()方法执行线程,间接调用run()方法。
ThreadDemo1类的代码:

public class ThreadDemo1
{
	public static void main(String args[]) throws Exception
	{
		new TestThread1().start();
		while(true)
		{
			System.out.println("main thread is running");
			Thread.sleep(1000);
		}
	}
}

class TestThread1 extends Thread
{
	public void run() 
	{
		while(true)
		{
			System.out.println(" TestThread1 is running");
			try {
				Thread.sleep(1000); //1000毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
} 

mainProgress类中的代码:

public class mainProgress {

	public static void main(String[] args) {
		new TestThread1.start();
		//如果start()方法调用一个以及启动的线程,系统会抛出lllegalThreadStateException异常		
	}
}

在main方法中,使线程执行需要调用Thread类中的start()方法,start()方法调用被覆盖的run()方法,如果不调用start()方法,线程永远无法启动,而在main中没有调用start()方法之前,Thread对象只是一个实例,并未成为真正的线程。

2)实现Runnable接口

从更本质的角度看,其实Thread类实现了Runnable接口,其中的run()方法正是对Runnable接口中的run()方法的具体实现。实现Runnable接口的程序会创建一个Thread对象,并将Runnable对象与Thread对象相关联。常用的两个构造方法:

public Thread(Runnable target)
public Thread(Runnable target , String name)

利用Runnable接口启动新线程步骤如下:
1)建立Runnable对象
2)使用参数为Runnable对象的构造方法创建Thread实例
3)调用start()方法启动线程

public class ThreadDemo2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();  //建立Runnable对象
        Thread thread = new Thread(runnable);  //创建Thread实例
        thread.start();  //启动线程
    }
}

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Created by Runnable..... ");
    }
}

注意:
启动一个新的线程,不是直接调用Thread子类对象的run()方法,而是调用Thread子类的start()方法,Thread类的start()方法产生一个新的线程,该线程运行Thread子类的run()方法。上述两种创建方式,工作时性质一样。但是建议使用实现Runable接口方式。解决单继承的局限性。

总结:

Java 多线程创建

有两种方式:

java.lang.Thread –线程继承Thread类,实现run方法

java.lang.Runnable接口 –线程实现Runnable接口,实现run方法
两种方法比较
–Thread占据了父类的名额,不如Runnable方便 (由于Java不支持多继承,却可以实现多个接口,因此,Runnable这个特性变得尤为重要)
–Thread 类实现Runnable
–Runnable启动时需要Thread类的支持
–Runnable 更容易实现多线程中资源共享

多线程启动

–start方法,会自动以新进程调用run方法
  
–直接调用run方法,将变成串行执行 

–同一个线程,多次start会报错,只执行第一次start方法 –多个线程启动,其启动的先后顺序是随机的 

–线程无需关闭,只要其run方法执行结束后,自动关闭  –main函数(线程)可能早于新线程结束,整个程序并不终止 

–整个程序终止是等所有的线程都终止(包括main函数线程)

最后再来两个例子加深理解:

public class ThreadDemo
{
	public static void main(String args[])
	{
		//new TestThread().start();
		//Runnable对象必须放在一个Thread类中才能运行
		TestThread tt= new TestThread();//创建TestThread类的一个实例
		Thread t= new Thread(tt);//创建一个Thread类的实例
		t.start();//使线程进入Runnable状态
		while(true)
		{
			System.out.println("main thread is running");
			try {
				Thread.sleep(1000); //1000毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
class TestThread implements Runnable //extends Thread
{
	//线程的代码段,当执行start()时,线程从此出开始执行
	public void run()
	{
		while(true)
		{
			System.out.println(Thread.currentThread().getName() +
			" is running");
			try {
				Thread.sleep(1000); //休眠1000毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
public class ThreadDemo2
{
	public static void main(String [] args)
	{
		TestThread4 t=new TestThread2();
		t.start();
		//t.start();//如果不注释掉,多次调用该方法会抛出异常
		TestThread4 t1=new TestThread2();
		t1.start();		
	}
}

class TestThread2 extends Thread  
{
	public void run()
	{
		while(true)
		{
			System.out.println(Thread.currentThread().getName() +
			" is running");
			try {
				Thread.sleep(1000); //休眠1000毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

常用的public方法:


Thread Thread.currentThread() :获得当前线程的引用。获得当前线程后对其进行操作。
Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() :返回线程由于未捕获到异常而突然终止时调用的默认处理程序。
int Thread.activeCount():当前线程所在线程组中活动线程的数目。
void dumpStack() :将当前线程的堆栈跟踪打印至标准错误流。
int enumerate(Thread[] tarray) :将当前线程的线程组及其子组中的每一个活动线程复制到指定的数组中。
Map<Thread,StackTraceElement[]> getAllStackTraces() :返回所有活动线程的堆栈跟踪的一个映射。
boolean holdsLock(Object obj) :当且仅当当前线程在指定的对象上保持监视器锁时,才返回 trueboolean interrupted() :测试当前线程是否已经中断。
void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) :设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。
void join() :等待该线程终止。
void join(long millis) :等待该线程终止的时间最长为 millis 毫秒。
void join(long millis, int nanos) :等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
void run() :线程启动后执行的方法。
void setContextClassLoader(ClassLoader cl) :设置该线程的上下文 ClassLoader。
void setDaemon(boolean on) :将该线程标记为守护线程或用户线程。
void start():使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
void sleep(long millis) :休眠指定时间
void sleep(long millis, int nanos) :休眠指定时间
void interrupt() :中断线程。
boolean isAlive() :测试线程是否处于活动状态。
boolean isDaemon() :测试该线程是否为守护线程。
boolean isInterrupted():测试线程是否已经中断。
void yield() :礼让,暂停当前正在执行的线程对象,并执行其他线程。
void checkAccess() :判定当前运行的线程是否有权修改该线程。
ClassLoader getContextClassLoader() :返回该线程的上下文 ClassLoader。
long getId() :返回该线程的标识符。
String getName() :返回该线程的名称。
int getPriority() :返回线程的优先级。
StackTraceElement[] getStackTrace() :返回一个表示该线程堆栈转储的堆栈跟踪元素数组。
Thread.State getState() :返回该线程的状态。
ThreadGroup getThreadGroup() :返回该线程所属的线程组。
Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() :返回该线程由于未捕获到异常而突然终止时调用的处理程序。
String toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

下一篇,将介绍有关线程的生命周期以及对线程的各种操作的方法。

posted @ 2020-03-19 18:58  零壹博弈  阅读(54)  评论(0)    收藏  举报