java线程基本使用(创建线程)
创建线程的两种方式
1.继承Thread类,重写run方法
演示:
1.编写程序,开启一个线程,该线程每隔1秒。在控制台输出“喵喵,我是小猫咪”
package threaduse;
public class Thread01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();//启动线程-> 最终会执行 cat
}
}
//说明
//1. 当一个类继承了 Thread 类, 该类就可以当做线程使用
//2. 我们会重写 run 方法,写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
@SuppressWarnings({"all"})
class Cat extends Thread{
@Override
public void run() {
while(true){
System.out.println("喵喵,我是小猫");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.对上题进行改进:当输出80次后,结束进程
package threaduse;
public class Thread01 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.start();//启动线程-> 最终会执行 cat
}
}
//说明
//1. 当一个类继承了 Thread 类, 该类就可以当做线程使用
//2. 我们会重写 run 方法,写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
@SuppressWarnings({"all"})
class Cat extends Thread{
@Override
public void run() {
int count=1;
while(true){
System.out.println("喵喵,我是小猫"+count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count!=80){
count++;
}
else{
break;
}
}
}
}
3.使用 JConsole 监控线程执行情况
package threaduse;
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
Cat cat = new Cat();
cat.start();//启动线程-> 最终会执行 cat
for (int i = 0; i < 60; i++) {
System.out.println("主线程i="+i);
Thread.sleep(1000);
}
}
}
//说明
//1. 当一个类继承了 Thread 类, 该类就可以当做线程使用
//2. 我们会重写 run 方法,写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
@SuppressWarnings({"all"})
class Cat extends Thread{
@Override
public void run() {
int count=1;
while(true){
System.out.println("喵喵,我是小猫"+count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count!=80){
count++;
}
else{
break;
}
}
}
}
主线程挂了,子线程不一定结束(通过以上例子说明主线程main退出后,子线程Thread-0继续执行)
为什么是调用start方法而不是run方法
案例
package threaduse;
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
Cat cat = new Cat();
// cat.start();//启动线程-> 最终会执行 cat
//读源码
/*
(1)
public synchronized void start() {
start0();
}
(2)
//start0() 是本地方法,是 JVM 调用, 底层是 c/c++实现
//真正实现多线程的效果, 是 start0(), 而不是 run
private native void start0();
*/
cat.run();
//cat.run();//run 方法就是一个普通的方法, 没有真正的启动一个线程,就会把 run 方法执行完毕,才向下执行
//说明: 当 main 线程启动一个子线程 Thread-0, 主线程不会阻塞, 会继续执行
//这时 主线程和子线程是交替执行
System.out.println("主线程继续执行" + Thread.currentThread().getName());//名字 main
for (int i = 0; i < 60; i++) {
System.out.println("主线程i="+i);
Thread.sleep(1000);
}
}
}
//说明
//1. 当一个类继承了 Thread 类, 该类就可以当做线程使用
//2. 我们会重写 run 方法,写上自己的业务代码
//3. run Thread 类 实现了 Runnable 接口的 run 方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
@SuppressWarnings({"all"})
class Cat extends Thread{
@Override
public void run() {
int count=1;
while(true){
System.out.println("喵喵, 我是小猫咪" + count + " 线程名=" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count!=80){
count++;
}
else{
break;
}
}
}
}
解释:
1.首先 start 方法调用 start0()方法
public synchronized void start(){
.....
start0();
.....
}
-
start0()是本地方法,是 JVM 调用,底层是c/c++实现
真正实现多线程的效果是 start0(),而不是run
private native void start0();
-
start()调用start0()方法后,该线程并不一定立马执行,只是将线程变成可运行状态。具体说明时候执行,取决于CPU,由CPU统一调度
2.实现Runnable接口,重写run方法
说明:
**1.**java是单继承,在某些情况下一个类可能继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了
**2.**java设计者提供了另一个方式创建线程,就是通过实现Runnable接口来创建线程
应用案例:
编写程序,可以每隔1秒,在控制台输出“小狗汪汪叫”,当输出10次后,自动退出。使用实现Runnable接口的方式实现
package threaduse;
public class Thread02 {
public static void main(String[] args) {
Dog dog = new Dog();
// dog.start();这里不能调用start
//创建了Thread对象,把dog对象,放入Thread
Thread thread = new Thread(dog);
thread.start();
}
}
@SuppressWarnings({"all"})
class Dog implements Runnable{
private int count=0;
@Override
public void run() {
while(true){
System.out.println("小狗汪汪叫..."+(++count)+"---"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count==10){
break;
}
}
}
}
编写一个程序,创建两个线程,一个线程每隔1秒输出“hello Thread”,输出10次退出,一个每隔1秒输出“hi”,输出5次退出
package threaduse;
public class Thread03 {
public static void main(String[] args) {
T1 t1 = new T1();
T2 t2 = new T2();
Thread thread0 = new Thread(t1);
Thread thread1 = new Thread(t2);
thread0.start();
thread1.start();
// new Thread(new T1()).start();//简写
}
}
class T1 implements Runnable{
private int count=0;
@Override
public void run() {
while(true){
System.out.println("hello Thread"+(++count)+"---"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count==10){
break;
}
}
}
}
class T2 implements Runnable{
private int count=0;
@Override
public void run() {
while(true){
System.out.println("hi"+(++count)+"---"+Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count==5){
break;
}
}
}
}
继承Thread vs 实现Runnable 的区别
**1.**从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别。
**2.**实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议使用Runnable