文章目录
1.线程的基本使用
创建线程的几种方式:
1.继承Thread类,重写run方法
2.继承Thread,使用匿名内部类
3.实现Runnable接口,重写run方法
4.实现Runnable,使用匿名内部类
5.创建线程最推荐的写法,使用lambda表达式最简单最直观的写法~~
1.1继承Thread类
- 当一个类继承了Thread类,该类就可以当作线程使用
- 重写run方法,在里面会写上自己的业务代码
代码演示:继承Thread类,重写run方法
package Thread;
class Fj extends Thread {//创建一个类继承Thread
@Override
public void run() {//重写run方法
while (true) {
System.out.println("hello");
try {
Thread.sleep(1000);//休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread fj = new Fj();
fj.start();//启动线程
//该线程每隔一秒输出hello
}
}
1.2继承Thread,使用匿名内部类
1.创建一个匿名内部类,继承Thread类重,写run方法
2.new 这个匿名内部类的实例
代码演示:继承Thread,使用匿名内部类
public class ThreadDemo1 {
public static void main(String[] args) {
Thread fj=new Thread(){//匿名内部类
@Override
public void run() {
System.out.println("hello fj");
}
};
fj.start();//启动线程
System.out.println("hello main");
}
}
1.3实现Runnable接口,重写run方法
由于java是单继承的,在某些情况下,一个类可能已经继承了某个父类,这时再用继承Thread类的方法来创建线程显然是不可能的了。
因此,java设计者,提供了另一种方法,就是通过实现Runnable接口来创建线程
代码演示:实现Runnable接口
package Thread;
class MyRunnable implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("hello fj");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo2 {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread fj = new Thread(runnable);
fj.start();
while (true) {
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1.4实现Runnable,使用匿名内部类
代码演示
package Thread;
public class ThreadDemo3 {
public static void main(String[] args) {
Thread fj=new Thread(){
public void run() {
while (true) {
System.out.println("hello fj");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
fj.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
1.5创建线程最推荐的写法使用lambda表达式!
lambda表达式,本质就是一个匿名函数
Java里面,函数(方法)是无法脱离类的,lambda就相当于是一个例外
lambda表达式的基本写法:
()->{ }
()里面放参数。
如果只有一个参数()可以省略
{ }里面放函数体
代码演示:lambda表达式
package Thread;
public class ThreadDemo5 {
public static void main(String[] args) {
Thread fj=new Thread(()->{
while (true){
System.out.println("hello fj");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
fj.start();
while (true){
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2多线程机制
通过Thread.currentThread().getName()来获取当前线程的名称
代码演示:创建一个线程获取他的名称
package Thread;
class Fj extends Thread {//创建一个类继承Thread
@Override
public void run() {//重写run方法
while (true) {
System.out.println("hello fj"+"线程名"+Thread.currentThread().getName());
try {
Thread.sleep(1000);//休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread fj = new Fj();
fj.start();//启动线程
}
}
在主线程添加一些业务代码观察执行过程
代码演示
package Thread;
class Fj extends Thread {//创建一个类继承Thread
@Override
public void run() {//重写run方法
while (true) {
System.out.println("hello fj"+"线程名"+Thread.currentThread().getName());
try {
Thread.sleep(1000);//休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread fj = new Fj();
fj.start();//启动线程
for (int i = 0; i <10; i++) {
System.out.println("主线程执行中"+i);
try {
Thread.sleep(1000);//同样休眠一秒;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
可见main线程和Thread-0线程交替执行
如图所示:上述程序 执行过程中,会打开一个进程,进入main主线程。当执行start时,会执行Thread-0子线程
当main线程启动一个子线程 Thread-0, 主线程不会阻塞, 会继续执行
3Thread类中run和start的区别
通过上述代码我们看到,无论以哪种方式创建,最终我们都会重写一个叫做 run 的方法,那为什么不直接调用run方法而是通过start呢?
代码演示:直接调用run方法
package Thread;
class Fj extends Thread {//创建一个类继承Thread
@Override
public void run() {//重写run方法
while (true) {
System.out.println("hello fj"+"线程名"+Thread.currentThread().getName());
try {
Thread.sleep(1000);//休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadDemo1 {
public static void main(String[] args) {
Thread fj = new Fj();
//fj.start();//启动线程
fj.run();
for (int i = 0; i <10; i++) {
System.out.println("主线程执行中"+i);
try {
Thread.sleep(1000);//同样休眠一秒;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
如果直接调用run方法则在主线程中运行
run方法就是一个普通的方法,没有真正的启动一个线程,就会阻塞在这里,直到run方法执行完毕才继续执行后续代码
Thread.java中start()方法的源码如下
public synchronized void start() {
// 如果线程不是"就绪状态",则抛出异常!
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 将线程添加到ThreadGroup中
group.add(this);
boolean started = false;
try {
// 通过start0()启动线程
start0();
// 设置started标记
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法.
start0()是本地方法,是JVM调用,底层是c/c++实现
真正实现多线程的效果,是start0(),而不是run