1、那些进程和线程之间你迷糊的事???
进程:正在运行的程序
线程:进程的最小执行单位
进程包含线程
dos系统是一个单线程的程序
java是一门支持多线程的语言
我们把含有main方法的线程也称为主线程
严格来说当启动一个java程序时,启动了两个线程,一个是主线程,还有一个垃圾回收器(garbage collection)
- 现在咱们测试下单个线程的执行情况
public class A {
public void testA() throws Exception{
System.out.println("testA方法开始执行");
Thread.sleep(5000);
System.out.println("testA方法执行完毕");
}
}
public class B {
public void testB() throws Exception{
System.out.println("testB方法开始执行");
Thread.sleep(5000);
System.out.println("testB方法开始完毕");
}
}
public class TestAB {
public static void main(String[] args) throws Exception {
A a = new A();
B b = new B();
a.testA();
b.testB();
}
}
由结果可以看出testA方法执行完毕之后才能执行testB方法,可见以上代码是单线程的
多线程可以充分利用cpu资源
对于单核cpu来说在同一时刻只能执行一个线程,但是切换速度很快,所以感觉是多个线程在同时执行
2、创建多线程常用的两种方式
- 方式一:
1)定义一个类继承Thread类
2)重写Thread类的run方法
3) 调用start方法开启多线程,start方法会自动调用run方法
在start方法中调用了private native void start0();方法,该方法有一个native关键字,表示该方法调用了底层的方法,通知cpu开启多线程
public class MyThread1 extends Thread{
@Override
public void run() {//线程任务
System.out.println("MyThread1开始执行了");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("MyThread1执行完毕了");
}
}
public class MyThread2 extends Thread{
@Override
public void run() {//线程任务
System.out.println("MyThread2开始执行了");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("MyThread2执行完毕了");
}
}
public class TestMyThread12 {
public static void main(String[] args) {
MyThread1 m1 = new MyThread1();
MyThread2 m2 = new MyThread2();
m1.start();
m2.start();
}
}
- 方式二:
1)定义一个类实现Runnable接口 2)创建该类对象,并传递到Thread类的构造方法中 3)调用Thread类的start方法
public class MyThread3 implements Runnable{
@Override
public void run() {
System.out.println("MyThread3开始执行了");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("MyThread3执行完毕了");
}
}
public class MyThread4 implements Runnable{
@Override
public void run() {
System.out.println("MyThread4开始执行了");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("MyThread4执行完毕了");
}
}
public class TestMyThread34 {
public static void main(String[] args) {
MyThread3 m3 = new MyThread3();
MyThread4 m4 = new MyThread4();
Thread t1 = new Thread(m3);
Thread t2 = new Thread(m4);
t1.start();
t2.start();
}
}
3、关于两种实现方式的使用问题
- 什么时候用接口什么时候用继承?
1.如果是is的关系时使用继承,例如男人是人
2.如果是has的关系时使用接口,例如:飞机有导航的功能,手机也有导航的功能 如果分不清楚时一律使用接口,因为一个类只能有一个父类,但是可以实现多个接口
4、在多线程环境下,如果某个线程抛出异常会不会影响其他线程?
- 测试一下 你就知道
public class MyThread5 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MyThread5的i=" + i);
if(i == 5) {
System.out.println(3 / 0);
}
}
}
}
public class TestMyThread5 {
public static void main(String[] args) {
MyThread5 m5 = new MyThread5();
m5.start();
for (int i = 0; i < 10; i++) {
System.out.println("主线程中的i=" + i);
}
}
}
由以上代码可以看出MyThread5中抛出的异常并没有影响主线程的执行
Thread-0,如果不给线程命名时,会自动命名Thread-0,Thread-1,Thread-2...
如果不给主线程命名时,会自动命名为"main"
5、线程命名
设置名称用setName
获取名称用getName
方式一:继承Thread类对线程设置名称
public class MyThread6 extends Thread{
public MyThread6(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + ":" + i);
}
}
}
public class TestMyThread6 {
public static void main(String[] args) {
MyThread6 m6 = new MyThread6("李四线程");
m6.setName("张三线程");
m6.start();
}
}
方式二:实现Runnable接口对线程起名
public class MyThread7 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//Thread.currentThread()获取当前线程对象
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
public class TestMyThread7 {
public static void main(String[] args) {
MyThread7 m7 = new MyThread7();
Thread t = new Thread(m7, "张三线程");
t.setName("李四线程");
Thread.currentThread().setName("王五线程");
t.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
6、设置线程的优先级
通过setPriority方法给线程设置优先级,参数是int类型,范围是1到10,值越大优先级越高
public class MyThread8 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(getName() + ":" + i);
}
}
}
public class TestMyThread8 {
public static void main(String[] args) {
MyThread8 m1 = new MyThread8();
m1.setName("线程a");
m1.setPriority(Thread.MIN_PRIORITY);//在开发时,如果使用数字尽量定义成常量
MyThread8 m2 = new MyThread8();
m2.setName("线程b");
m2.setPriority(Thread.NORM_PRIORITY);
MyThread8 m3 = new MyThread8();
m3.setName("线程c");
m3.setPriority(Thread.MAX_PRIORITY);
m1.start();
m2.start();
m3.start();
}
}
7、守护线程
m.setDaemon(true);//让普通线程变成守护线程,守护着主线程,一旦主线程结束,那么该线程必须结束
垃圾回收器是一个典型的守护线程
public class MyThread9 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(getName() + ":" + i);
}
}
}
public class TestMyThread9 {
public static void main(String[] args) {
MyThread9 m = new MyThread9();
m.setDaemon(true);//让普通线程变成守护线程,守护着主线程,一旦主线程结束,那么该线程必须结束
m.start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程:" + i);
if(i == 50) {
System.out.println(3 / 0);
}
}
}
}
8、线程的生命周期
生命周期:指的是对象从创建到消亡的过程,在每个过程中调用的方法称为生命周期方法

public class TestMyThread6 {
public static void main(String[] args) {
MyThread6 m6 = new MyThread6();
Thread t = new Thread(m6,"李四线程");
t.start();
//如果一个线程已经执行完毕,不能再次执行它,否则会抛出Illegal(非法)Thread(线程)State(状态)Exception(异常)
t.start();
}
}
9、如何让线程停止
示例代码:
public class MyThread7 extends Thread{
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程:" + i);
if(i == 50){
// stop();
// return;//结束整个方法
break;
}
}
System.out.println("关闭资源代码");
}
}
设置标志位的代码:
stop方法,和return方法都让整个线程任务结束,如果有关闭资源的代码时不会被执行,所以如果提前让线程结束最好是定义一个标志位或者使用break
public class MyThread7 extends Thread{
public void run() {
boolean flag = true;
for (int i = 0; flag; i++) {
System.out.println("线程:" + i);
if(i == 50){
// stop();
// return;//结束整个方法
flag = false;
// break;
}
}
System.out.println("关闭资源代码");
}
}
记得点赞关注👉:推荐自己的Github地址:github.com/Lmobject