什么是进程,什么是线程
- 进程是一个应用程序
- 现场是进程中的一个执行场景
- 一个进程可以启用多个线程
多线程并发
- 在java语言中,线程A和线程B,堆内存和方法区内存共享,但是栈内存独立,一个线程一个栈
- 如果启动10个线程,那么就会有10个栈,每个栈与栈之间互不干涉,各自执行各自的,这就是多线程并发
实现线程
- java支持多线程机制,并且java已经将多线程实现了,我们只需要继承就行了
方式一:编写一个类,直接继承java.lang.Thread,重写run方法
/*
实现多线程的第一种方式:
编写一个类,直接继承java.lang.Thread,重写run方法
怎样创建线程对象? new一个就行
怎样启动线程? 调用线程对象的start()方法
*/
public class ThreadTest02 {
public static void main(String[] args) {
//这里是main方法,这里的代码属于主线程,在主栈运行
//新建一个分支线程对象
MyThread myThread = new MyThread();
//启动线程
//start()方法的作用:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后,瞬间就结束了。
//线程启动成功会自动调用run()方法,并且run方法在分支栈的栈底部(压栈)。
//run方法在分支栈的最底部,main方法在主栈的最底部。run和main是平级的
myThread.start();
//这里的代码还是运行在主线程中
for (int i = 0; i < 1000; i++) {
System.out.println("主线程---->" +i);
}
}
}
class MyThread extends Thread{
@Override
public void run() {
//编写程序,这段代码运行在分支线程中(分支栈)
for (int i = 0; i < 1000; i++) {
System.out.println("分支线程---->"+i);
}
}
}
方式二:编写一个类,实现java.lang.Runnable接口,实现run方法
public class ThreadTest03 {
public static void main(String[] args) {
//创建一个可运行的对象
MyRunnable r = new MyRunnable();
//将可运行的对象封装成一个线程对象
Thread t = new Thread(r);
//启动线程
t.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程---->" +i);
}
}
}
//这并不是一个线程类,是一个可运行的类,它还不是一个线程。
class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程---->" +i);
}
}
}
注意:第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,使用起来更加灵活
方式三:实现Callable接口,这种方式可以获取线程的返回值。效率低,主方法会受阻。
/*
实现线程的第三种方式:
实现Callable接口
*/
public class ThreadTest13 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//第一步:创建一个“未来任务”对象
FutureTask task = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {
//call方法想当于run方法,只是有返回值
//模拟执行
System.out.println("call method begin!");
Thread.sleep(1000*10);
System.out.println("call method end!");
int a = 100;
int b = 200;
return a+b;
}
});
//创建线程对象
Thread t = new Thread(task);
t.start();
//获取t线程的返回值
Object o = task.get();
System.out.println("线程执行结构:"+o);
//main方法这的程序要想执行,必须等get方法执行结束
System.out.println("你好,各位!");
}
}
使用匿名内部类创建多线程
/*
采用匿名内部类
*/
public class ThreadTest04 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程--->"+i);
}
}
});
//启动线程
t.start();
for (int i = 0; i < 100; i++) {
System.out.println("主线程--->"+i);
}
}
}
线程对象的生命周期
- 新建状态
- 就绪状态
- 运行状态
- 阻塞状态
- 死亡状态
线程的sleep方法
/*
关于线程sleep方法:
static void sleep(long millis)
1、静态方法:Thread.sleep(1000);
2、参数是毫秒
3、作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其它线程使用
这行代码出现在A线程中,A线程就会进入休眠
这行代码出现在B线程中,B线程就会进入休眠
*/
public class ThreadTest05 {
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"------>"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
所以,当我们设置时间过长时,想中途停止sleep方法,改怎样做?
/*
如何终止sleep方法
*/
public class ThreadTest06 {
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable2());
t.setName("t");
t.start