多线程基础
Posted whalesea
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程基础相关的知识,希望对你有一定的参考价值。
一、线程和进程
一般都知道,线程是被包含在进程里的,一个进程可以有多个线程同时存在。
进程是资源分配的最小空间,线程是cpu调度的最小单位。
进程和线程的区别:
1、线程不能看做独立应用,而进程可看做独立应用。
2、进程有独立的地址空间,互相不影响,线程只是进程的不同执行路径。
3、线程没有独立的地址空间,多进程的程序比多线程程序健壮。
4、进程的切换比线程的切换开销大。
java中线程和进程的关系:
1、java对操作系统提供的功能进行封装,包括进程和线程。
2、运行一个java程序会产生一个进程,进程包含至少一个进程。
3、每个进程对应一个JVM实例,多个线程共享JVM里的堆。
4、java采用单线程编程模型,程序会自动创建主线程。
5、主线程可以创建子线程,原则上要后于子线程完成执行。
二、Thread和Runnable,创建线程
Runnable是一个函数式接口,内部只有一个public abstract void run()的抽象方法,所以它本身是不带有多线程的功能的。Thread是实现了Runnable接口的类,它的start方法才使得run()里的代码支持多线程特性。
由于java的单一继承原则,推荐使用Runnable。例如可以将业务类实现Runnable接口,将业务逻辑封装在run方法里,将给业务类作为参数传递给Thread类,可以实现多线程的特性。但是,如果通过继承Thread类的方式实现多线程,那么业务类将无法继承其他类。
另外:Runnable里的资源可以共享,下面使用代码比较说明:
使用Thread:
public class MyThread extends Thread { int count = 5; @Override public void run() { while (count > 0){ System.out.println(Thread.currentThread().getName()+ ":" + count); count--; } } }
public class ThreadDome { public static void main(String[] args){ Thread thread1 = new MyThread(); Thread thread2 = new MyThread(); Thread thread3 = new MyThread(); thread1.start(); thread2.start(); thread3.start(); } }
运行结果:
Thread-0:5 Thread-0:4 Thread-0:3 Thread-0:2 Thread-1:5 Thread-1:4 Thread-0:1 Thread-1:3 Thread-1:2 Thread-1:1 Thread-2:5 Thread-2:4 Thread-2:3 Thread-2:2 Thread-2:1
使用Runnable:
public class MyRunnable implements Runnable { private int count = 5; @Override public void run() { while (count > 0){ System.out.println(Thread.currentThread().getName() +":"+ count); count--; } } }
public class RunnableDome { public static void main(String[] args){ MyRunnable myRunnable1 = new MyRunnable(); Thread thread1 = new Thread(myRunnable1); Thread thread2 = new Thread(myRunnable1); Thread thread3 = new Thread(myRunnable1); thread1.start(); thread2.start(); thread3.start(); } }
结果:
Thread-0:5 Thread-1:5 Thread-0:4 Thread-0:2 Thread-1:3 Thread-0:1
三、Thread类中的Run和Start方法的区别
先说一下结论:它们都可以实现启动run方法里的逻辑,区别是,run方法调用的主线程,start方法调用的是新创建的线程。
1、代码说明:
先是run方法:
public class ThreadTest { public static void attack(){ System.out.println("Current thread is :" + Thread.currentThread().getName()); } public static void main(String[] args){ Thread r = new Thread(){ @Override public void run() { attack(); } }; System.out.println("Current main thread is :" + Thread.currentThread().getName()); r.run(); } }
结果:
Current main thread is :main
Current thread is :main
可以发现,当前线程是main
start方法:
public class ThreadTest { public static void attack(){ System.out.println("Current thread is :" + Thread.currentThread().getName()); } public static void main(String[] args){ Thread r = new Thread(){ @Override public void run() { attack(); } }; System.out.println("Current main thread is :" + Thread.currentThread().getName()); r.start(); } }
结果:
Current main thread is :main
Current thread is :Thread-0
可以发现,当前线程是新创建的Thread-0.
2、为什么会这样?
首先,run方法是Runnable的一个抽象方法,Thread类重写这个方法的源码如下:
@Override public void run() { if (target != null) { target.run(); } }
target就就是当做参数传入的Runnable接口。如果是通过参入Runnable 参数实现的Thread,就调用Runnable的run方法;而如果没有传入Runnable接口,那么targer会为空,这时意味着,run方法被Thread的继承类重写或是被匿名内部类重写,则会调用相应的重写run方法。
但是,通过上述代码没有找到新线程的创建的逻辑,是因为,新线程的创建在Thread类的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 */ } } }
继续查看start0的方法:
private native void start0();
这里是调用了外部的源码,继续查找(查看源码网址:链接):
{"start0", "()V", (void *)&JVM_StartThread},
调用jvm包里的JVM_StartThread方法(链接):
其中关键:
native_thread = new JavaThread(&thread_entry, sz);
继续查看:thread_entry方法:
static void thread_entry(JavaThread* thread, TRAPS) { HandleMark hm(THREAD); Handle obj(THREAD, thread->threadObj()); JavaValue result(T_VOID); JavaCalls::call_virtual(&result, obj, KlassHandle(THREAD, SystemDictionary::Thread_klass()), vmSymbols::run_method_name(), vmSymbols::void_method_signature(), THREAD); }
最终在创建线程之后,调用run方法(vmSymbols::run_method_name())。
所以start的逻辑就是:先调用底层代码创建线程,然后返回调用run方法。
以上是关于多线程基础的主要内容,如果未能解决你的问题,请参考以下文章