如何创建一个多线程:
Java提供了java.lang.Thread类,这就是线程的定义类,包含了:线程的优先级,线程id、线程状态等线程的基本信息。
通过Thread类的说明,可以知道创建线程的两种方式:1 extends Thread类,2 implements Runnable接口
1 继承Thread类
package com.thread;
public class ThreadCreate {
public static void main(String[] args) {
Thread t = new MyThread(new User("jkf"));
t.start();
}
}
class MyThread extends Thread{
private User u;
public MyThread(User u){
this.u = u;
}
//重写run方法
public void run(){
System.out.println("this is my Thread "+Thread.currentThread().getName());
u.printName();
}
}
class User{
private String name;
public User(String name){
this.name=name;
}
public void printName(){
System.out.println("this is "+name);
}
}
输出:
this is my Thread Thread-0
this is jkf
这是最简单的方法,创建一个线程,通过重写run方法,可以实现一些自定义的操作。
通过查看Thread类的run方法,
public void run() {
if (target != null) {
target.run();
}
}
还可以通过设置target对象,调用target的run方法,而private Runnable target; 是一个Runnable对象,而Thread提供这样的构造函数。这就是创建多线程的第二种方式:实现Runnable接口
2 实现Runnable接口
package com.thread;
public class ThreadCreateRunnable {
public static void main(String[] args) {
Printer printer = new Printer(new User("jkf"));
new Thread(printer).start();
}
}
class Printer implements Runnable{
private User u;
public Printer(User u) {
this.u=u;
}
public void run() {
u.printName();
}
}
输出内容:
this is jkf
通过提取print方法,通过Printer实现Runnable接口,实现线程的创建。
两者的区别:
1 一个是通过继承Thread类实现,一个通过实现Runnable接口实现,建议通过实现Runnable接口来创建线程,因为java类支持多实现,单继承,如果继承Thread类,那么就不能继承其他类了。
在Thread中,还有一个run(),通过上述的两个例子,发现我们启动线程都是通过start方法,而线程最后调用的仍然是run方法,那么为什么直接调用run方法,即t.run()。这涉及到jvm的底层,如果要创建一个线程那么就必须通过start方法,这才是真正的生成一个新的线程。
实例:
public static void main(String[] args) {
Thread t = new MyThread(new User("jkf"));
t.run();
}
//把方法一种的t.start()修改为t.run(),输出如下:
this is my Thread main
this is jkf
t.start()的输出如下:
this is my Thread Thread-0
this is jkf
两者的主要区别就是this is my Thread Thread-0中Thread的名称。
其中main表示的是主线程,即main线程,因为启动main方法,那么就是一个进程,一个进程对应一个线程,因此main线程就是最初的线程,而Thread-0是通过main创建的新线程。因此可以发现:t.start()创建了Thread-0,而t.run()却仍然是主线程在调用,因此并不会创建新线程。
因此启动一个线程必须通过.start方法。
技巧
当我们创建一个线程时,最好给该线程使用一个有含义的名称,这样排查起来方便,看到线程名称就知道是使用于什么业务。
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
}
},"com.csdn.trade.createOrder");
小思考
前面说到,进程可以有多个线程,多个线程共用进程的内存等内容,思考:1个进程创建了3个线程,如果有一个线程内存溢出了,请问另外两个线程怎么样了?
-----main方法执行上述方法前,请配置main方法的jvm参数,防止电脑跟着一起挂了
vm option:
-Xms1m -Xmx1m -XX:+HeapDumpOnOutOfMemoryError
同时为了好查看,最好把输出内容输出到文件中,这样通过文件进行查看
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
List<String[]> list = new ArrayList<>();
while(true){
System.out.println("this is thread"+Thread.currentThread().getName()+",我要内存512");
String[] arr = new String[512];
list.add(arr);
}
}
},"thread-512").start();
new Thread(new Runnable() {
@Override
public void run() {
List<String[]> list = new ArrayList<>();
while(true){
System.out.println("this is thread"+Thread.currentThread().getName()+",我要内存2048");
String[] arr = new String[2048];
list.add(arr);
}
}
},"thread-2048").start();
new Thread(new Runnable() {
@Override
public void run() {
List<String[]> list = new ArrayList<>();
while(true){
System.out.println("this is thread"+Thread.currentThread().getName()+",我要内存1024");
String[] arr = new String[1024];
list.add(arr);
}
}
},"thread-1024").start();
}
--- 截取一部分输出内容
this is threadthread-1024,我要内存1024
this is threadthread-512,我要内存512
this is threadthread-1024,我要内存1024
this is threadthread-512,我要内存512
this is threadthread-512,我要内存512
this is threadthread-1024,我要内存1024
this is threadthread-512,我要内存512
this is threadthread-1024,我要内存1024
Exception in thread "thread-512" java.lang.OutOfMemoryError: Java heap space
at cn.gov.zcy.vaccine.plan.dto.VaccinePlanProductsDto$1.run(VaccinePlanProductsDto.java:57)
at java.lang.Thread.run(Thread.java:745)
this is threadthread-1024,我要内存1024
this is threadthread-1024,我要内存1024
this is threadthread-1024,我要内存1024
this is threadthread-1024,我
通过输出内容,可以看到两个线程都在运行,后来512的线程内存溢出,但是1024的线程继续执行