首页 > 其他分享 >Thread 之 run() 方法

Thread 之 run() 方法

时间:2023-01-05 22:22:46浏览次数:32  
标签:run Thread t1 线程 null 方法 public

案例代码一

@Slf4j
public class Client {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }     
}

class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
    }
}

线程调用 start() 方法之后,操作系统的任务调度器就会对线程进行调度,线程进入就绪状态,然后等待分配 CPU 时间片,如果线程分配到了 CPU 时间片,操作系统底层就会执行 run() 方法

MyThread 类继承自 Thread 类,同时重写了 run 方法,对于线程来说,如果它分配到了 CPU 时间片,操作系统底层最终调用的是当前线程类的 run() 方法(可以简单的理解为运行状态下的线程只认 run() 方法)

如果多写一个 MyThread 类不够优雅,那么可以使用匿名内部类的方式

@Slf4j
public class Client {
    public static void main(String[] args) {
        Thread t1 = new Thread() {
            @Override
            public void run() {
                log.info("t1 start...");
            }
        };
    }
}

  

案例代码二

@Slf4j
public class Client {
    public static void main(String[] args) {
        Runnable runnable = ()->{
            log.info("t1 start...");
        };

        Thread t1 = new Thread(runnable, "t1");
        t1.start();
    }
}

使用 Runnable + Thread 方式实现的多线程,run() 方法是如何被调用的呢

我们跟踪 new Thread(runnable,"t1") 这段代码

public Thread(Runnable target, String name) {
	init(null, target, name, 0);
}

private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
	init(g, target, name, stackSize, null, true);
}

private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {
	if (name == null) {
		throw new NullPointerException("name cannot be null");
	}

	this.name = name;
	Thread parent = currentThread();
	SecurityManager security = System.getSecurityManager();
	if (g == null) {
		if (security != null) {
			g = security.getThreadGroup();
		}
		if (g == null) {
			g = parent.getThreadGroup();
		}
	}
	g.checkAccess();
	if (security != null) {
		if (isCCLOverridden(getClass())) {
			security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
		}
	}

	g.addUnstarted();

	this.group = g;
	this.daemon = parent.isDaemon();
	this.priority = parent.getPriority();
	if (security == null || isCCLOverridden(parent.getClass()))
		this.contextClassLoader = parent.getContextClassLoader();
	else
		this.contextClassLoader = parent.contextClassLoader;
	this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext();
	
	// 将传进来的 Runnable 实现类对象赋值给成员变量 target		
	this.target = target;
	setPriority(priority);
	if (inheritThreadLocals && parent.inheritableThreadLocals != null)
		this.inheritableThreadLocals =
			ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
	this.stackSize = stackSize;
	tid = nextThreadID();
}

通过上面的源码得知,我们使用 Thread 带参构造方法传递进来的 Runnable 接口的实现类对象最终赋值给了 Thread 类的成员变量 Runnable target

当线程调用 start() 方法会进入到就绪状态,紧接着获取到 CPU 时间片之后会进入运行状态,运行状态的线程只会去调度当前线程类的 run() 方法

上面案例中当前线程类是 Thread 类的一个实例,找到 Thread run 方法

@Override
public void run() {
	// 如果 Runnable 类型的成员变量不为 null,则调用成员变量的 run() 方法
	if (target != null) {
		target.run();
	}
}

而通过上面我们已经知道了成员变量的 target 就是我们传递进来的 runnable,所以最终调用的是 runnable 对象的 run 方法

 

案例代码三

@Slf4j
public class Client {
    public static void main(String[] args) {
        FutureTask<String> futureTask = new FutureTask(()->{
            log.info("t1 start...");
            return "hello xiao mao mao!";
        });

        Thread t1 = new Thread(futureTask, "t1");
        t1.start();
    }
}

在跟代码之前先看一下 FutureTask 的继承体系吧

通过整个体系可以看出 FutureTask 也是 Runnable 接口的一个具体实现类

通过案例二可以得知使用 Thread t1 = new Thread(futureTask, "t1") 这种方式创建线程对象的时候,如果线程进入运行状态,实际上调用的是 Runnable 实现类的 run() 方法,而我们这里的 FutureTask 就是 Runnable 接口的实现类,所以运行状态的线程最终调用的是 futureTask 的 run() 方法

接着看一下 FutureTask 类的 run() 方法是怎么实现的

public void run() {
	if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread()))
		return;
	try {
		// 将成员变量 callable 赋值给变量 c
		Callable<V> c = callable;
		if (c != null && state == NEW) {
			V result;
			boolean ran;
			try {
				// 调用 Callable 实现类对象的 call 方法
				result = c.call();
				ran = true;
			} catch (Throwable ex) {
				result = null;
				ran = false;
				setException(ex);
			}
			if (ran)
				set(result);
		}
	} finally {
		runner = null;
		int s = state;
		if (s >= INTERRUPTING)
			handlePossibleCancellationInterrupt(s);
	}
}

从源码可以看出在 futureTask 对象的 run() 方法中实际上是 Callable 接口实现类的 call() 方法在执行

所以 Callable + FutureTask + Thread 这种方式下,当线程处于运行状态下时,真正执行业务逻辑的是 Callable 实现类的 call() 方法,该方法是对 run() 方法的一个增强,call() 方法可以抛出异常,也可以有返回值,而这些特性 run() 方法都不支持

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

  

 

标签:run,Thread,t1,线程,null,方法,public
From: https://www.cnblogs.com/xiaomaomao/p/17028986.html

相关文章

  • BST查找结构与折半查找方法的实现与实验比较
    简介作业:查找结构与排序方法作业题目:BST查找结构与折半查找方法的实现与实验比较要求编写程序实现BST存储结构的建立(插入)、删除、查找和排序算法;实现折半查找算法......
  • JQuery:常用方法一览
    代码CodehighlightingproducedbyActiproCodeHighlighter(freeware)http://www.CodeHighlighter.com/-->Attribute:$(”p”).addClass(css中定义的样式类型);给某个元......
  • 三位毫秒数产生随机数方法
    #1三位随机数是获取电子硬件的毫秒级时间戳,从后到前的读取三个数字,把它们组合成三位数。(例如毫秒级时间戳1672673902720,获得的三位数是027。毫秒级时间戳是一个十多位的......
  • 关于爬虫中几个常用库的使用方法总结
    关于爬虫中几个常用库的使用方法总结学了半个多月的爬虫了,用这个案例总结一下各个爬虫库的用法。当然后面还有更重要和更好用的方法,再等后面学到,再做总结了。1.目标......
  • Java中next() 、nextInt() 和 nextLine() 方法
    Scanner的几个常用next输入方法要点next():一直接收从键盘中打入的内容直到读取到回车,此回车并不会被读取,且一定要读取到有效字符后才可以结束输入。对输入有效字符之......
  • Thread 之 start() 方法
    案例代码@Slf4jpublicclassClient{publicstaticvoidmain(String[]args){Threadt1=newThread("t1"){@Overridepu......
  • 【VS Code】c++环境配置 && .vscode文件 && Code Runner的exe文件指定生成位置
    因为一些奇奇怪怪的问题重装了系统,所以重新配置了vscode,上次配置vscode时由于没有用过,所以环境配置一头雾水,甚至还有些历史遗留问题,一直都是在凑活着用,这次刚好重新开始。......
  • Linux时间戳转换成易读格式的方法
    背景最近一直在学习Redis相关的知识.其中遇到了一个redismonitor的命令但是这里有一个问题是:原生命令查询出来的时间是Unix时间戳格式的.不太好发现查看与进行对照......
  • Address支付方法send,transfer,call
    Send:具有返回值,2300gwei限制用法:boolname1=address.send(msg.value)//msg.value为转入值 Transfer:无返回值,2300gwei限制用法:address.transfer(msg.value) Call:......
  • adb获取app包名的方法
    一、手机或模拟器上已安装app(美团为例)方法一:在命令行输入adbshellammonitor,按Enter,再启动想要获取的app(包名在最后一行:com.sankuai.meituan)C:\Users\starteos>adbshe......