Java中的线程

java程序是多线程的

为什么说java程序是多线程的呢?

直接看下面这个简单的main方法,粗略一看好像并没有启动其他线程,但是实际结果并非如此。

package com.su.mybatis.oracle.controller;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;

public class Main {
    public static void main(String[] args) {
        //Java 虚拟机线程系统的管理接口
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        // 不需要获取同步的monitor和synchronizer信息,仅仅获取线程和线程堆栈信息
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
        // 遍历线程信息,仅打印线程ID和线程名称信息
        for (ThreadInfo threadInfo : threadInfos) {
            System.out.println(threadInfo.getThreadId() + "--" + threadInfo.getThreadName());
        }
    }
}

输出结果:

5--Attach Listener  //内存dump,线程dump,类信息统计,获取系统属性等
4--Signal Dispatcher  //分发处理发送给JVM信号的线程
3--Finalizer  //调用对象finalize方法的线程
2--Reference Handler  //清除Reference的线程
1--main  //main线程,用户程序入口

上面输出结果明确地说明了只执行一个简单的main方法,但是jdk启动了5个线程来执行,因此,java程序是多线程的。值得注意的是,main方法开始执行才会生成这几个线程,但是它们都是平等的。

线程的优先级

线程的优先级范围1~10,默认优先级为5。理论上来说,优先级越高,能获得更多的时间片分配,可以适当给需要更多时间片的线程(I/O操作)设置更高的优先级,但是这也不是必然的,操作系统也可能忽略线程的优先级。

package com.su.mybatis.oracle.controller;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        t.start(); 
    }
}


class TestThread extends Thread{
    @Override
    public void run() {
        Thread currentThread = Thread.currentThread();//当前线程
        System.out.println("线程名称:" + currentThread.getName());
        System.out.println("线程优先级:" + currentThread.getPriority());
    }
}

运行结果:

线程名称:Thread-0
线程优先级:5

 设置线程名称和优先级,运行

    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();
        t.setName("TestThread");//线程名字
        t.setPriority(10);//优先级  1~10 
        t.start(); 
    }

运行结果:

线程名称:TestThread
线程优先级:10

守护线程

守护线程是一种程序运行时,在后台调度提供支持性服务的线程。当非守护线程都结束时,jdk会强制关闭所有守护线程,jvm会退出,这也就意味着守护线程里面有可能不会进行资源回收。垃圾回收线程就是守护线程。

设置方式:

TestThread t = new TestThread();
t.setDaemon(true);//true:守护线程

线程的实现方式

打开Thread.class,类描述明确说明创建线程有且只有两种方式:继承Thread类和实现Runable接口

1)、继承Thread类

package com.su.mybatis.oracle.controller;

public class TestThread extends Thread{
    
    @Override
    public void run() {
        //TODO
        System.out.println("1111111111");
    }
}

2)、实现Runable接口

package com.su.mybatis.oracle.controller;

public class TestRunnable implements Runnable{

    @Override
    public void run() {
        //TODO
        System.out.println("2222222222");
    }

}

线程启动

package com.su.mybatis.oracle.controller;

public class Main {
    public static void main(String[] args) {
        TestThread t1 = new TestThread();
        t1.start();
        TestRunnable t2 = new TestRunnable();
        new Thread(t2).start() ;
    }
}

运行结果:

1111111111
2222222222

注意:线程调用start()方法时会校验线程状态,如果线程已经调用过start()方法,会抛出java.lang.IllegalThreadStateException。

同一个线程调用两次start()的方法如下所示:

package com.su.mybatis.oracle.controller;

public class Main {
    public static void main(String[] args) {
        TestThread t1 = new TestThread();
        t1.start();
        t1.start();
    }
}

上面方法会抛出异常,因为start()中对线程状态校验:

 if (threadStatus != 0)
            throw new IllegalThreadStateException();

Thread与Runnable的区别

准确来说,Thread才是Java里对线程的唯一抽象,Runnable只是对任务(业务逻辑)的抽象。Thread可以接受任意一个Runnable的实例并执行。

举个例子:周末,你在打游戏,你女朋友在追剧;快到饭点了,你女朋友做饭,你帮忙切菜;你们吃完饭后,一起去看电影.....那么在这个例子中,你和你女朋友都可以看成是一个Thread,而打游戏、追剧、做饭、切菜、吃饭、看电影等这些都可以看成是一个Runnable。Thread可以接受任意一个Runnable的实例并执行意味着你可以去追剧,你女朋友可以去打游戏等等。

线程中止

1)、自然终止

线程执行完;

抛出异常提前结束。

2)、suspend()、stop()

suspend(),线程进入睡眠状态,需要等待唤醒,但是会占据资源,会造成死锁问题;

stop(),强制终止线程,不能保证占据资源正常释放,比如,上传图片过程中使用了stop()会导致图片损坏。

因为以上方法的特性,所有不建议使用上述方法,jdk中这些方法都是过期的。

3)、安全中止

interrupt(),修改中断线程标志位为true,对线程中断,但是并不是强制的,也就是说这个方法只是通知线程需要中断,实际上线程可以不理会中断请求而继续执行;

isInterrupted(),检查线程标志位,true:线程被中断,false:线程不被中断;

Thread.interrupted(),与isInterrupted()作用相同,但是会将中断标志位改为false。

举个例子:

Main.java

package com.su.mybatis.oracle.controller;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        TestThread t1 = new TestThread();
        t1.start();
        TestThread.sleep(10);//保证线程在while中运行一段时间
        t1.interrupt();//设置线程中断标志位true
    }
}

TestThread .java

package com.su.mybatis.oracle.controller;

public class TestThread extends Thread{
    
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println("1-线程(" + threadName + ")中断标志:" + isInterrupted());
        while(true){//--判断标志1
//        while(!isInterrupted()){//--判断标志2
//        while(!Thread.interrupted()){//--判断标志3
            System.out.println("------");
            System.out.println("2-线程(" + threadName+")中断标志:" + isInterrupted());
        }
//        System.out.println("3-线程(" + threadName+")中断标志:" + isInterrupted());
    }
}

当TestThread.java中while使用判断标志1时,启动Main.java中的main方法,会发现虽然将线程得中断标志位设置为true,但是while中的打印并不会停止,线程并没有理会中断请求而继续执行;

------
2-线程(Thread-0)中断标志:true
------
2-线程(Thread-0)中断标志:true
.
.
.

当while使用判断标志2时,加上‘3-线程...’的打印(删除前面的//),启动main方法,一段时间后,线程中止,控制台输出如下:

1-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
.
.
.
------
2-线程(Thread-0)中断标志:true
3-线程(Thread-0)中断标志:true

当while使用判断标志3时,加上‘3-线程...’的打印,启动main方法,一段时间后,线程中止,控制台输出如下:

1-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
------
2-线程(Thread-0)中断标志:false
.
.
.
------
2-线程(Thread-0)中断标志:true
3-线程(Thread-0)中断标志:false

中断异常

sleep()、wait()、join()等方法,会抛出中断异常,把中断标志位会由true改成false,所以在中断异常中需要手动中断,为了避免关闭线程时,没有释放资源。

注意:处于死锁状态的线程是无法被中断的。

 

 

如果有写的不对的地方,请大家多多批评指正,非常感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值