进程与线程
进程与线程
进程内存独立不共享
线程堆内存共享,栈独立,一个线程一个栈
分析一个问题,单核电脑能不能实行多线程并发?
多核肯定没问题
例:4核CPU表示同一时间点上,可以实现四个进程并发执行
单核不能真正的实现多线程并发:
但是Cpu的处理速度很快,多个线程之间频繁切换,给人一种多线程的感觉
创建多线程的方式
1:继承java.lang.Thread,重写run方法
package AboutThread;
public class AboutThread {
public static void main(String[] args) {
myThread myThread = new myThread();
myThread.start();
// start()方法的作用是在内存中开辟一个新的栈空间,完成之后瞬间结束,这行代码只是为了开辟一个栈空间
// 启动成功的线程会自动调用run方法,run方法在分支栈的栈底部,run和main方法是同级的
// myThread.run();此方法不会开辟栈空间,不会并发执行
for (int i = 0; i < 100; i++) {
System.out.println("主线程");
// 通过输出发现,有的有的有先有后,有多有少
}
}
}
class myThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程");
}
}
}
2:编写一个类,实现java.lang.Runnable接口
package AboutThread;
public class ThreadTest02 {
public static void main(String[] args) {
// 创建一个可运行的对象
MyThread02 myThread02=new MyThread02();
// 将可运行的对象封装成一个线程对象
Thread thread=new Thread(new MyThread02());
thread.start();
}
}
/*这不是一个线程类*/
class MyThread02 implements Runnable{
@Override
public void run() {
}
}
注意
第二种方法最常用,因为一个类实现了一个接口还可以继承别的类,更灵活
线程生命周期
1:新建状态
start()->就绪状态
就绪状态的线程又叫做可运行状态,表示当前线程具有抢夺CPU时间片的权力(CPU时间片就是执行权)
当一个线程抢夺到CPU时间片之后,就开始执行run方法
run方法开始执行标志着线程进入运行状态
2:运行状态
当之前占有的CPU时间片用完之后,会重新回到就绪状态继续抢夺CPU时间片,
当再次抢到之后会重新进入run方法接着上一次的代码继续运行
run方法结束之后->死亡状态
线程在就绪状态与运行状态频繁切换
运行状态--->遇到阻塞事件--->阻塞状态
3:阻塞状态
当一个线程遇到阻塞状态,例如获取用户输入,此时线程会进入阻塞状态,
阻塞状态的线程会放弃之前占有的CPU时间片
阻塞解除之后会进入就绪状态继续抢夺CPU时间片
线程对象生命周期:
新建状态
就绪状态
运行状态
阻塞状态
死亡状态
获取和修改线程名
修改线程的名字:setName(),getName()
当线程没有设置名字时:
默认的名字是:Thread-0,Thread-1
获取当前线程对象
static Thread currentThread()
package Thread;
public class AboutThread {
public static void main(String[] args) {
Thread t1 = Thread.currentThread();
// t1就是当前线程对象
// 这行代码在main方法中,所以当前线程就是主线程
System.out.println(t1.getName());
}
}
class MyThread extends Thread {
@Override
public void run() {
Thread t2 = Thread.currentThread();
super.getName();
System.out.println(t2.getName());
}
}
sleep()
源码: public static native void sleep(long millis) throws InterruptedException;
静态方法sleep是使当前线程进入阻塞状态,跟对象无关
package AboutThread;
public class ThreadTest02 {
public static void main(String[] args) {
// 创建一个可运行的对象
// 将可运行的对象封装成一个线程对象
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("123");
}
});
thread.start();
try {
thread.sleep(1000);
//
//
// 这里的sleep方法是使主线程进入阻塞状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
睡眠sleep()
package AboutThread;
public class SleepTest {
public static void main(String[] args) {
MyRunnable myRunnable=new MyRunnable();
Thread t=new Thread(myRunnable);
t.setName("t1");
t.start();
try {
Thread.sleep(5*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.interrupt();
// 干扰,中断线程的睡眠
// 这种中断异常的方式依靠了Java的异常处理机制,让线程的睡眠抛出异常,之后输出异常,结束睡眠
}
}
class MyRunnable implements Runnable{
@Override
// run()方法无法throws,因为父类没有抛出异常,子类不能比父类抛出更多异常
public void run() {
System.out.println(Thread.currentThread().getName()+"正在运行");
try {
Thread.sleep(1000*60*10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"结束");
}
}
合理的终止线程
package AboutThread;
/*
stop()
stop会直接终止进程,容易丢失数据,已过时
*/
public class StopThread {
public static void main(String[] args) {
MyRunnable2 runnable2 = new MyRunnable2();
Thread t1 = new Thread(runnable2);
t1.start();
try {
t1.sleep(1000 * 5);
//主线程模拟睡眠5秒
} catch (InterruptedException e) {
e.printStackTrace();
}
//5秒之后执行此语句,终端线程01
runnable2.run = false;
}
}
class MyRunnable2 implements Runnable {
boolean run = true;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (run) {
System.out.println(Thread.currentThread().getName() + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else
// 可以添加结束线程之前的代码
return;
// 结束线程
}
}
}

浙公网安备 33010602011771号