线程的创建方式
1:通过继承Thread类创建一个线程类.子类重写Thread的run方法即可.
public class ThreadTwoTest extends Thread{
public static void main(String[] args) {
ThreadTwoTest threadTwoTest = new ThreadTwoTest();
threadTwoTest.start();
}
@Override
public void run() {
System.out.println("我实现了Thread,我是一个线程子类.");
}
}
2:通过继承Runnable接口创建一个线程.
public class ThreadThreeTest implements Runnable {
public static void main(String[] args) {
ThreadThreeTest threadThreeTest = new ThreadThreeTest();
Thread thread = new Thread(threadThreeTest);
thread.start();
}
@Override
public void run() {
System.out.println("我是通过实现Runnable接口实现的一个线程类.");
}
}
3:使用Cllable接口创建线程,泛型可以指定返回的类型.
public class ThreadCallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ReturnableTask returnableTask = new ReturnableTask();
FutureTask<String> futureTask = new FutureTask<String>(returnableTask);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
static class ReturnableTask implements Callable<String> {
@Override
public String call() throws Exception {
return "我实现了callable接口创建了线程,拿到了返回结果";
}
}
}
4:通过线程池创建线程.
public class ThreadPoolTest {
public static void main(String[] args) {
//定长线程池.
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//缓存线程池.
ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
//定时线程池.
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
//单例线程池.
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
}
}
通过了解线程的创建方式可以看到最基础的还是Thread这个类.它的结构如下.
线程ID | 属性: private long tid |
获取线程Id | 方法: public long getId() |
线程名称 | 属性: private String name |
获取线程名称 | 方法一: public final String getName() |
设置线程名称 | 方法二: public final void setName(String name) |
构造方法设置名称 | 方法二: Thread(String threadName) |
线程优先级 | 属性: private int priority |
获取线程优先级 | 方法一: public int getPriority() |
设置线程优先级 | 方法二: public final void setPriority(int priority) |
是否为守护线程 | 属性: private boolean daemon =false |
设置为守护线程 | 方法: public final void setDaemon(boolean on) |
线程的状态 | 属性: private int threadStatus |
获取线程状态 | 方法: public Thread.State getState() |
线程状态 | 属性: NEW(新建) |
属性: RUNNABLE(就绪运行) | |
属性: BLOCKED(阻塞) | |
属性: WAITING(等待) | |
属性: TIMED_WAITING(计时等待) | |
属性: TERMINATED(结束) | |
线程的启动 | 方法: public void start() |
线程的运行 | 方法: public void run() |
获取当前线程 | 方法: public staic Thread currentThread() |
表格里总结了一些比较主要的属性和方法,还有其他一些重要的属性,具体可以进入源码在细细品味.
public class ThreadOneTest {
public static void main(String[] args) {
Thread thread = new Thread();
//线程的名字.
System.out.println("线程的名字--" + thread.getName());
//线程的id.
System.out.println("线程的id--" + thread.getId());
//线程状态.
System.out.println("线程状态--" + thread.getState());
//线程的优先级.
System.out.println("线程的优先级--" + thread.getPriority());
thread.start();
}
}
Thread的创建方式.
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
空参构造方法.
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
传入一个Runnable实例.
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
传入线程组和Runnable实例.
public Thread(String name) {
init(null, null, name, 0);
}
指定一个线程名称.
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
传入线程组和指定线程名称.
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
传入Runnable实例和指定线程名称.
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
传入线程组和Runnable实例和指定线程名称.
了解了Thread类的构造方法,会发现核心应该是这个Runnable接口.
public class Thread implements Runnable{
}
而且Thread类实现了这个接口.这个接口有一个方法,
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
看到里的话.是不是就清楚了Thread和Runnable这两种创建线程的联系.java支持类的单继承,接口是多实现.Runnable接口增强了创建线程的灵活性.拓展性也强了.(当然很官话,还是忍不住想要分享一下自己的一个感觉,虽然不一定对,但是还是很开心有所收获).
从run方法可以看出来,不支持返回值.所以就引入了Callable接口.
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
它的返回值是一个泛型.看到这里返回头看下Thread的start()方法做了什么.
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) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
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();
this.target = target;
setPriority(priority);
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
/* Set thread ID */
tid = nextThreadID();
}
重点在这里 this.target = target;这个target就是我们传入的Runnable实例.
@Override
public void run() {
if (target != null) {
target.run();
}
}
最后执行的就是Runnable接口的run方法,也就是我们实现的那个方法.所以那么问题就来了,callable是怎么进行的呢.一个实现了RunnableFuture接口的FutureTask<v>类就出现了.启到一个承上启下.
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
看到这个是不是一下子就恍然大悟,是不是有一种适配器的感觉油然而生.
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
Callable<V> c = callable;这个实例就是实现了callable接口的对象.里面最终会执行result = c.call();最后会把result值放到outcome这个属性里.
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
最后就可以通过FutureTask<v>对象的get方法取到线程的返回值.
关于线程池就等后面在具体介绍吧.因为我是第一次写技术博客,好多东西可能并不是那么完美.有不足的地方希望大家可以多多指教.不管什么时候,大家都是进步的.我也是一样,既然选择开始,那就坚持这个开始.
标签:null,Thread,方式,创建,void,Runnable,线程,多线程,public From: https://blog.csdn.net/m0_68082638/article/details/140583752