Java 线程创建与常用方法

进程与线程

进程

线程

进程与线程的区别

并行与并发

单核 cpu 下,线程实际还是 串行执行 的。操作系统中有一个组件叫做任务调度器,将 cpu 的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是: 微观串行,宏观并行 。一般会将这种 线程轮流使用 CPU 的做法称为并发 (concurrent)

多核 cpu下,每个 核(core) 都可以调度运行线程,这时候线程可以是并行的。

Java 线程

创建和运行线程

Thread 与 Runnable 的关系

线程运行的原理

栈与栈帧

每个线程启动后,虚拟机就会为其分配一块栈内存。

线程上下文切换

因为以下一些原因导致 cpu 不再执行当前的线程,转而执行另一个线程的代码

当 Context Switch 发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java 中对应的概念就是程序计数器(Program Counter Register),它的作用是记住下一条 jvm 指令的执行地址,是线程私有的

常见方法

方法名

static

功能说明

注意

start()


启动一个新线程,在新的线程运行 run 方法中的代码

start 方法只是让线程进入就绪,里面的代码不一定立刻运行(CPU的时间片还没有分给它)。每个线程对象的 start 方法只能调用一次,否则会出现异常

run()


新线程启动后会调用的方法

如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法。但可以创建 Thread 的子类对象来覆盖默认行为

join()


等待线程运行结束


join(long n)


等待线程运行结果,最多等待 n 毫秒


getId()


获取线程长整型的 id


getName()


获取线程名


setName(String)


修改线程名


getPriority()


获取线程优先级


setPriority(int)


修改线程优先级

java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率

getState()


获取线程状态

Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED

isInterrupted()


判断是否被打断

不会清除 打断标记

isAlive()


线程是否存活(还没有运行完毕)


interrupt()


打断线程

如果被打断线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;park 的线程被打断,也会设置 打断标记

interrupted()

static

判断当前线程是否被打断

会清除 打断标记

currentThread()

static

获取当前正在执行的线程


sleep(long n)

static

让当前执行的线程休眠 n 毫秒,休眠时让出 CPU 的时间片给其他程序


yield()

static

提示线程调度器让出当前线程对CPU的使用

主要是为了测试和调试

start 与 run

调用 run

public static void main(String[] args) {
 	Thread t1 = new Thread("t1") {
 		@Override
 		public void run() {
 			log.debug(Thread.currentThread().getName());
 			FileReader.read(Constants.MP4_FULL_PATH);
 		}
 	};
    
 	t1.run();
 	log.debug("do other things ...");
}

输出

19:39:14 [main] c.TestStart - main
19:39:14 [main] c.FileReader - read [1.mp4] start ...
19:39:18 [main] c.FileReader - read [1.mp4] end ... cost: 4227 ms
19:39:18 [main] c.TestStart - do other things ...

程序仍在 main 线程运行, FileReader.read() 方法调用还是同步的

总结

sleep 与 yield

sleep

yield

线程优先级

join

等待一个线程执行结束

等待多个线程的结果

Java 线程创建与常用方法

情况一:

package testJoin;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.demo1")
public class demo1 {

    static int r = 0 , r1 = 0 , r2 = 0;

    public static void main(String[] args) throws InterruptedException {
        test2();
    }

    private static void test2() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                r1 = 10;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(2000);
                r1 = 20;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        log.debug("join begin");
        t1.join();
        log.debug("t1 join end");
        t2.join();
        log.debug("t2 join end");
        long end = System.currentTimeMillis();
        log.debug("r1: {} r2: {} cost: {}",r1,r2,end-start);
    }
}

输出:

14:18:02 [main] c.demo1 - join begin
14:18:03 [main] c.demo1 - t1 join end
14:18:04 [main] c.demo1 - t2 join end
14:18:04 [main] c.demo1 - r1: 20 r2: 0 cost: 2008

情况二:

package testJoin;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.demo1")
public class demo1 {

    static int r = 0 , r1 = 0 , r2 = 0;

    public static void main(String[] args) throws InterruptedException {
        test2();
    }

    private static void test2() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
                r1 = 10;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t2 = new Thread(() -> {
            try {
                Thread.sleep(2000);
                r1 = 20;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long start = System.currentTimeMillis();
        t1.start();
        t2.start();
        log.debug("join begin");
        t2.join();
        log.debug("t2 join end");
        t1.join();
        log.debug("t1 join end");
        long end = System.currentTimeMillis();
        log.debug("r1: {} r2: {} cost: {}",r1,r2,end-start);
    }
}

输出:

14:19:19 [main] c.demo1 - join begin
14:19:21 [main] c.demo1 - t2 join end
14:19:21 [main] c.demo1 - t1 join end
14:19:21 [main] c.demo1 - r1: 20 r2: 0 cost: 2006

另外 join 也可以带参数,是有时效的等待。当到设定时间线程还未给出结果,直接向下运行,不再等待。如果设定时间还没到但是线程已经执行完毕,则直接向下执行,不再等待。

interrupt

打断 sleep,wait,join 的线程

这几个方法都会让线程进入阻塞状态

打断 sleep 的线程, 会清空打断状态,以 sleep 为例

package testInterrupt;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.demo1")
public class demo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("sleep...");
            try {
                Thread.sleep(5000);
                //注意:sleep,wait,join等被打断并以异常形式表现出来后
                // 会把打断标记重新置为 false(未打断状态)
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"t1");

        t1.start();
        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
        log.debug("打断标记:{}",t1.isInterrupted());
    }
}

输出:

15:08:12 [t1] c.demo1 - sleep...
15:08:13 [main] c.demo1 - interrupt
15:08:13 [main] c.demo1 - 打断标记:false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at testInterrupt.demo1.lambda$main$0(demo1.java:11)
	at java.lang.Thread.run(Thread.java:748)

Process finished with exit code 0

打断正常运行的线程打断标记置为:true

package testInterrupt;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.demo2")
public class demo2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true){
                boolean interrupted = Thread.currentThread().isInterrupted();
                if(interrupted){
                    log.debug("被打断了,退出循环");
                    break;
                }
            }
        },"t1");
        t1.start();

        Thread.sleep(1000);
        log.debug("interrupt");
        t1.interrupt();
    }
}

输出:

15:17:40 [main] c.demo2 - interrupt
15:17:40 [t1] c.demo2 - 被打断了,退出循环

打断 park 线程

package testInterrupt;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.LockSupport;

@Slf4j(topic = "c.demo4")
public class demo4 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            log.debug("park...");
            LockSupport.park();
            log.debug("unpark...");
            log.debug("打断状态:{}",Thread.currentThread().isInterrupted());
        },"t1");

        t1.start();

        Thread.sleep(1000);
        t1.interrupt();
    }
}

输出:

14:16:21 [t1] c.demo4 - park...
14:16:22 [t1] c.demo4 - unpark...
14:16:22 [t1] c.demo4 - 打断状态:true

两阶段终止模式

Java 线程创建与常用方法

package testInterrupt;

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.demo3")
public class demo3 {
    public static void main(String[] args) throws InterruptedException {
        TwoPhaseTermination tpt = new TwoPhaseTermination();
        tpt.start();
        Thread.sleep(3500);
        tpt.stop();
    }
}

@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination{
    private Thread monitor;

    //启动监控线程
    public void start(){
        monitor = new Thread(() -> {
            while (true){
                Thread current = Thread.currentThread();
                if(current.isInterrupted()){
                    log.debug("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);//情况1
                    log.debug("执行监控记录");//情况2
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    //重新设置打断标记
                    current.interrupt();
                }
            }
        });

        monitor.start();
    }

    //终止监控线程
    public void stop(){

        monitor.interrupt();
    }
}

输出:

15:33:02 [Thread-0] c.TwoPhaseTermination - 执行监控记录
15:33:03 [Thread-0] c.TwoPhaseTermination - 执行监控记录
15:33:04 [Thread-0] c.TwoPhaseTermination - 执行监控记录
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at testInterrupt.TwoPhaseTermination.lambda$start$0(demo3.java:29)
	at java.lang.Thread.run(Thread.java:748)
15:33:04 [Thread-0] c.TwoPhaseTermination - 料理后事

Process finished with exit code 0

不推荐的方法

还有一些不推荐使用的方法,这些方法已过时,容易破坏同步代码块,造成线程死锁

方法名

static

功能说明

stop()


停止线程运行

suspend()


挂起(暂停)线程运行

resume()


恢复线程运行

来源:https://www.cnblogs.com/lcha-coding/p/16341851.html

展开阅读全文

页面更新:2024-05-04

标签:线程   方法   优先级   指令   标记   进程   内存   状态   常用   时间   程序

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top