前言
之前在学校学习线程,就是很简单的学习创建和使用,一般也没用过线程,因为在学校根本用不到并发。线程的好处有很多:提高资源利用率,让电脑的资源充分利用起来;可以提高程序的运行速度;等等。
在公司,一般都会用到线程开发,juc的高并发开发、线程池的使用。一般这线都是在学校用不到也学不到的,所以我之前也没有搞过、学习过。所以我现在用到了,我就写个博客,记录一下,学习一下。
我想记录的东西有很多,也不知道能写多少,我尽力哈。
- 线程基础
- 线程状态
- 线程同步
- JUC高并发
- 线程池
一、线程简介
1.概述
线程
是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。- 在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
- 线程是
独立调度
和分派
的基本单位。
简单一点解释
- 方法间调用:普通方法调用,从哪里来到哪里去,闭合的一条路径。
- 多线程使用:开辟了多条路径。
2.进程、线程 区别
区别 | 进程 | 线程 |
---|---|---|
根本区别 | 作为资源分配的单位 | 调度和执行的单位 |
开销 | 每隔进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销。 | 线程可以看成轻量级的进程,同一类线程共享赛马和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。 |
所处环境 | 再操作系统中能同时运行多个任务(程序) | 再同一应用中有多个顺序流同时执行 |
分配内存 | 系统再运行的时候会为每个进程分配不同的内存区域 | 除了CPU之外,不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源 |
包含关系 | 没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的。 | 线程是进程的一部分,所以线程有的时候被称为是清权进程或者轻量级进程 |
注意:很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核,如服务器。如果是 模拟出来的多线程,即一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为 切换的很快,所以就有同时执行的错觉。
3. 核心概念
• 线程就是独立的执行路径;
• 在程序运行时,即使没有自己创建线程,后台也会存在多个线程, 如gc线程、主线程;
• main()称之为主线程,为系统的入口点,用于执行整个程序;
• 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排 调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的 干预的;
• 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控 制;
• 线程会带来额外的开销,如cpu调度时间,并发控制开销
• 每个线程在自己的工作内存交互,加载和存储主内存控制不当会 造成数据不一致。
二、 线程创建
1.概述
线程创建有三种方式,如图所示:第三种实现Callable方式 是juc高级编程里的方式,目前只知道就可以啦。
2. 第一种方式继承Thread
1) 继承Thread
package com.feng.ch01_thread;
/**
* 创建线程方式一:
* 1. 创建:继承Thread + 重写run
* 2. 启动: 创建子类对象 + start方法
*/
public class StartThread extends Thread {
@Override
public void run() {
for (int i = 0 ; i<20; i++){
System.out.println("一边唱歌");
}
}
public static void main(String[] args) {
// 创建子类对象
StartThread startThread = new StartThread();
// 启动
startThread.start(); // 不保证立即运行, CPU 调用
// startThread.run(); // 普通方法调用
for (int i = 0; i< 20 ; i++){
System.out.println("一遍coding");
}
}
}
2) 示例:下载图片
package com.feng.ch02_webdownload;
public class ThreadDownload extends Thread {
private String url; //远程路径
private String name; // 存储名字
public ThreadDownload(String url, String name){
this.url = url;
this.name = name;
}
@Override
public void run() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.download(url, name);
System.out.println(name);
}
public static void main(String[] args) {
ThreadDownload td01 = new ThreadDownload("http://article-fd.zol-img.com.cn/t_s500x2000/g1/M01/01/0F/ChMljV2C4SuIZfJoAABdiz-TYC8AAP2EQDL4VIAAF2j137.jpg", "phone.jpg");
ThreadDownload td02 = new ThreadDownload("http://tblg.k-img.com/restaurant/images/Rvw/12277/12277487.jpg", "spl.jpg");
ThreadDownload td03 = new ThreadDownload("http://thumbs.dreamstime.com/b/key-success-to-18466568.jpg", "success.jpg");
td01.start();
td02.start();
td03.start();
}
}
3. 第二种方式:实现Runnable
- 创建目标对象: IDownloader id =new IDownloader(“图片地址”,“baidu.png”);
- 创建线程对象+关联目标对象: Thread t =new Thread(id);
- 启动线程: t.start()
package com.feng.ch01_thread;
/**
* 创建线程方式二:
* 1. 创建:实现implement + 重写run
* 2. 启动: 创建实现类对象 + Thread对象 + start方法
*
* 推荐:避免单继承的局限性,优先使用接口
* 方面共享资源
*/
public class StartRunnable implements Runnable {
@Override
public void run() {
for (int i = 0 ; i<20; i++){
System.out.println("一边唱歌");
}
}
public static void main(String[] args) {
/*
// 创建实现类对象
StartRunnable startThread = new StartRunnable();
// 创建代理类对象
Thread ch01_thread = new Thread(startThread);
//启动
ch01_thread.start();
*/
// 链式写法
new Thread(new StartThread()).start();
for (int i = 0; i< 20 ; i++){
System.out.println("一遍coding");
}
}
}
5. 第三种方式:实现Callable
- 创建目标对象: StartCallableDownload_simple cd =new StartCallableDownload_simple ();
- 创建执行服务: ExecutorService ser=Executors.newFixedThreadPool(3); // 3个线程
- 提交执行: Future result1 =ser.submit(cd1) ;
- 获取结果: boolean r1 =result1.get();
- 关闭服务: ser.shutdownNow();
package com.feng.ch04_callable;
import java.util.concurrent.*;
public class StartCallableDownload_simple implements Callable<Integer> {
@Override
public Integer call() {
System.out.println("name:"+Thread.currentThread().getName());
return 0;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1、 创建目标对象
StartCallableDownload_simple scd01 = new StartCallableDownload_simple();
StartCallableDownload_simple scd02 = new StartCallableDownload_simple();
StartCallableDownload_simple scd03 = new StartCallableDownload_simple();
// 高级的juc 编程(java.util.concurrent),
// 2、创建执行服务
ExecutorService executorService = Executors.newFixedThreadPool(6); // 6个线程
// 3、提交执行
Future<Integer> result01 = executorService.submit(scd01);
Future<Integer> result02 = executorService.submit(scd02);
Future<Integer> result03 = executorService.submit(scd03);
// 4、获取结果 这里需要抛出 两个 异常
Integer aBoolean = result01.get();
Integer aBoolean1 = result02.get();
Integer aBoolean2 = result03.get();
System.out.println(aBoolean2);
// 5、关闭服务
executorService.shutdown();
}
}
5. Thread对比Runnable
6. 线程示例
1) 龟兔赛跑
package com.feng.ch01_thread;
/**
* 模拟龟兔赛跑
*/
public class RacerRunnable implements Runnable {
public static void main(String[] args) {
RacerRunnable racerRunnable = new RacerRunnable();
new Thread(racerRunnable, "tortoise").start();
new Thread(racerRunnable, "rabbit").start();
}
private String winner;// 胜利者
@Override
public void run() {
for (int step = 1; step <= 100; step++){
// 模拟兔子休息
if (Thread.currentThread().getName().equals("rabbit") && (step%10==0)){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"-->"+step);
// 比赛是否结束
boolean b = gameOver(step);
if (b){
break;
}
}
}
public boolean gameOver(int step){
if (winner!=null){
return true;
}else{
if (step == 100){
winner = Thread.currentThread().getName();
System.out.println("winner==>"+ winner);
return true;
}
}
return false;
}
}
2) 12306购票
package com.feng.ch03_bugticket03;
/**
* 共享资源, 并发(线程安全)
*/
public class Web12306 implements Runnable {
// 票数
private int ticketNums = 99;
@Override
public void run() {
while (true){
if (ticketNums<0){
break;
}
// 模拟网络延迟
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
public static void main(String[] args) {
// 一份资源
Web12306 web12306 = new Web12306();
System.out.println(Thread.currentThread().getName());
// 多份代理
new Thread(web12306, "码畜").start();
new Thread(web12306, "码农").start();
new Thread(web12306, "码蟥").start();
}
}
出现了负数和重复数据,则出现了 共享资源、线程安全 的问题。
三、静态代理和动态代理
概念:使用一个代理对象将对象包装起来,然后用该代理对象来取代该对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时调用原始对象的方法
1. 静态代理
1) 概述
要求被代理类和代理类同时实现相应的一套接口,通过代理类调用重写接口的方法,实际上调用的是原始对象的同样的方法
Cilent调用Source的method()方法,实际上是Proxy来调用method()方法,静态代理中Source跟Proxy都要实现接口Sourceable。
2) 示例
首先是父接口 Animal.java
package com.feng.springboottest.other.staticproxy;
public interface Animal {
public void action();
public void breath();
}
Cat.java
package com.feng.springboottest.other.staticproxy;
// 被代理的类
public class Cat implements Animal {
@Override
public void action() {
System.out.println("喵喵喵~~~~~~~");
}
@Override
public void breath() {
System.out.println("喵式呼吸法~~~~~~~");
}
}
CatProxy.java
package com.feng.springboottest.other.staticproxy;
// 代理类
public class CatProxy implements Animal {
//真正要代理的类
Cat cat;
public CatProxy(Cat cat) {
this.cat = cat;
}
@Override
public void action() {
System.out.println("==========catProxy 代理类执行开始!=============");
//实质上在代理类中是调用了被代理实现接口的方法
cat.action();
System.out.println("==========catProxy 代理类执行结束!===========");
}
@Override
public void breath() {
System.out.println("==========catProxy 代理类执行开始!=============");
cat.breath();
System.out.println("==========catProxy 代理类执行结束!===========");
}
}
TestCatStaticProxy.java
package com.feng.springboottest.other.staticproxy;
public class TestCatStaticProxy {
public static void main(String[] args) {
//被代理的类Cat,Cat实现了Animal接口
Cat cat = new Cat();
//代理类CatProxy,也实现了Animal接口
CatProxy catProxy = new CatProxy(cat);
//代理类来调用方法,实际上调用的是Cat的action(),breath()方法
catProxy.action();
catProxy.breath();
}
}
运行结果:
从运行结果可以看到其实执行的是被代理类的对象.
从这里我们会想,如果我想再创建一个Dog对象,又需要重新为Dog创建一个代理对象,如下:
public class Dog implements Animal {
@Override
public void action() {
System.out.println("汪汪汪~~~~~~~");
}
@Override
public void breath() {
System.out.println("狗式呼吸法~~~~~~~");
}
}
package com.feng.springboottest.other.staticproxy;
public class DogProxy implements Animal {
Dog dog;
public DogProxy(Dog dog) {
this.dog = dog;
}
@Override
public void action() {
System.out.println("==========dogProxy 代理类执行开始!=============");
//实质上在代理类中是调用了被代理实现接口的方法
dog.action();
System.out.println("==========dogProxy 代理类执行结束!===========");
}
@Override
public void breath() {
System.out.println("==========dogProxy 代理类执行开始!=============");
//实质上在代理类中是调用了被代理实现接口的方法
dog.action();
System.out.println("==========dogProxy 代理类执行结束!===========");
}
}
package com.feng.springboottest.other.staticproxy;
public class TestDogStaticProxy {
public static void main(String[] args) {
Dog dog = new Dog();
DogProxy dogProxy = new DogProxy(dog);
dogProxy.action();
dogProxy.breath();
}
/**
* 每次我要新加入一个实现Animal接口的对象的话,都要重新创建一个代理对象,这样会非常的麻烦,
* 这其实是静态代理的缺点,动态代理
*/
}
每次我要新加入一个实现Animal接口的对象的话,都要重新创建一个代理对象,这样会非常的麻烦,
这其实是静态代理的缺点,
接下来就看 动态代理吧
2. 动态代理
1) 概述
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象,下面直接看代码:
2) 示例
还是Animal.java
package com.feng.springboottest.other.staticproxy.dynamicproxy;
public interface Animal {
public void action();
public void breath();
}
Cat
package com.feng.springboottest.other.staticproxy.dynamicproxy;
// 被代理类
public class Cat implements Animal {
@Override
public void action() {
System.out.println("喵喵喵~~~~");
}
@Override
public void breath() {
System.out.println("猫式呼吸法~~~~");
}
}
Dog.java
package com.feng.springboottest.other.staticproxy.dynamicproxy;
public class Dog implements Animal {
@Override
public void action() {
System.out.println("汪汪汪~~~~~");
}
@Override
public void breath() {
System.out.println("狗式呼吸法~~~~");
}
}
MyProxy.java
package com.feng.springboottest.other.staticproxy.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyProxy implements InvocationHandler {
Object obj;
public MyProxy() {
}
public MyProxy(Object obj) {
this.obj = obj;
}
/**
*代理类调用方法时,都会调用invoke方法
* @param proxy
* @param method 代理对象执行的方法
* @param args 参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("==============代理类开始执行!!!!=============");
//returnVal是方法的返回值
Object returnVal = method.invoke(obj, args);
System.out.println("==============代理类执行结束!!!!=============");
return returnVal;
}
}
ProxyUtil.java
package com.feng.springboottest.other.staticproxy.dynamicproxy;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static Object getProxyInstance(Object obj){
MyProxy proxy = new MyProxy(obj);
/*
* obj.getClass().getClassLoader():被代理对象的类加载器
* obj.getClass().getInterfaces() :被代理对象 实现 的接口 (因为只有一个接口)
* proxy : 实现InvocationHandler的接口
*
* 实质上是通过反射将 被代理类的加载器 和接口 与代理对象 关联起来
* obj :是被代理的对象
*/
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), proxy);
}
}
TestDynamicProxy.java
package com.feng.springboottest.other.staticproxy.dynamicproxy;
import com.feng.springboottest.other.staticproxy.Cat;
public class TestDynamicProxy {
public static void main(String[] args) {
Cat cat = new Cat();
// 获取 代理类的 实例(通过反射)
Object proxyInstance = ProxyUtil.getProxyInstance(cat);
Animal animal = (Animal) proxyInstance;
animal.action();
animal.breath();
Dog dog = new Dog();
Object proxyInstance1 = ProxyUtil.getProxyInstance(dog);
Animal animal1 = (Animal) proxyInstance1;
animal1.action();
animal1.breath();
}
}
动态代理的代理对象是 在运行时动态创建目标类的代理对象,而静态代理是需要为每个目标类创建代理对象,动态代理只需要一个方法就可以,相比静态代理代码冗余量减少了。
四、 lambda表达式创建进程
从普通的thread实现 到jdk8的实现的转化,
从静态内部类-》局部内部类-》匿名内部类-》lambda表达式
package com.feng.ch06_lambdaThread;
public class LambdaThread {
// 第一次简化:静态内部类
static class Test01 implements Runnable{
@Override
public void run() {
System.out.println("一边听歌");
}
}
public static void main(String[] args) {
new Thread(new Test01()).start();
//第二次简化:局部内部类
class Test02 implements Runnable{
@Override
public void run() {
System.out.println("一边看书");
}
}
new Thread(new Test02()).start();
// 第三次简化: 匿名内部类, 必须借助接口或者父类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("一边coding");
}
}).start();
// 第四次简化: jdk8 简化 lambda表达式
new Thread(()->{
System.out.println("一边学习");
}).start();
}
}
五、 线程状态
1. 概述
- 新生状态:一旦 Thread thread = new Thread();线程对象就进入了新生状态。
- 就绪状态:进入其状态的四个情况
thread.start();
解除阻塞中方法;
thread.yield方法; 高风亮节,让出线程,让本线程进入就绪状态
jvm切换,jvm将cpu从本地线程切换到其他线程。 - 运行状态:一定会从就绪状态被CPU调度到了,才会进行运行
- 堵塞状态:其发生的四个情况
Thread.sleep();占着资源休眠。
thread.wait(); 不占资源,站在一边等待。
thread.join; 加入、合并、插队,等别人用完资源,在用。
read 、write; 通过操作系统调用 - 死亡状态:
stop(); 不推荐使用,不安全。过时。
destroy();不推荐使用,不安全。过时。
一般是让代码执行完,或者想方设法让代码执行完。设置标志。
2. 线程方法
- sleep ()
• 使线程停止运行一段时间,将处于阻塞状态
• 如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行! - join ()
• 阻塞指定线程等到另一个线程完成以后再继续执行。 合并线程,也指插入线程。 - yield ()
• 让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态;
• 调用了yield方法之后,如果没有其他等待执行的线程,此时当前线程就会马上恢复执行! - setDaemon()
• 可以将指定的线程设置成后台线程,守护线程;
• 创建用户线程的线程结束时,后台线程也随之消亡;
• 只能在线程启动之前把它设为后台线程 - setPriority(int newPriority) getPriority()
• 线程的优先级代表的是概率
• 范围从1到10,默认为5 - stop()停止线程
• 不推荐使用
1) 线程停止
- 不使用JDK提供的stop()/destroy()方法(它们本身也被JDK废弃了)。
- 提供一个boolean型的终止变量,当这个变量置为false,则终止线程的运行。
package com.feng.state;
/**
* 终止线程
* 1、线程正常执行完毕-->次数
* 2、外部干涉 -->加入标识
* 不要使用stop destroy
*
*/
public class ch01_TerminateThread implements Runnable {
//1、加入标识 标记线程体是否可以运行
private boolean flag = true;
private String name;
public ch01_TerminateThread(String name) {
this.name = name;
}
//3、对外提供方法改变标识
public void terminate() {
this.flag = false;
}
@Override
public void run() {
int i=0;
//2、关联标识,true-->运行 false -->停止
while(flag) {
System.out.println(name+"-->"+i++);
}
}
public static void main(String[] args) {
ch01_TerminateThread tt = new ch01_TerminateThread("C罗");
new Thread(tt).start();
for(int i=0;i<=99;i++) {
if(i==88) {
tt.terminate();//线程的终止
System.out.println("tt game over");
}
System.out.println("main-->"+i);
}
}
}
2) Sleep()
拿住当前对象或者资源,进行占用而不使用,让 本身进程 和 其他消费该对象或者资源的进程 进入堵塞状态。这个特点是针对wait()方法而言。
这是一个静态方法,使用:Thread.sleep()。因为是 Thread,所以是当前的进程进行堵塞。
一般使用sleep()方法 进行模拟网络延时,在模拟网络延时的时候,放大了出现问题的概率。
• sleep(时间)指定当前线程阻塞的毫秒数;
• sleep存在异常InterruptedException;
• sleep时间达到后线程进入就绪状态;
• sleep可以模拟网络延时、倒计时等。
• 每一个对象都有一个锁,sleep不会释放锁;
a) 示例1 模拟12306 抢票
package com.feng.state;
/**
* sleep模拟网络延时,放大了发生问题的可能性
*
*/
public class ch02_BlockedSleep01 {
public static void main(String[] args) {
//一份资源
Web12306 web =new Web12306();
System.out.println(Thread.currentThread().getName());
//多个代理
new Thread(web,"码畜").start();
new Thread(web,"码农").start();
new Thread(web,"码蟥").start();
}
}
class Web12306 implements Runnable{
//票数
private int ticketNums = 99;
@Override
public void run() {
while(true) {
if(ticketNums<0) {
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->"+ticketNums--);
}
}
}
一般来说 资源只有一份,进程堵塞的时候,会加大出现问题的情况,会出现负数和重复的情况,这个问题使用线程同步或者锁来进程解决,下面会讲到。
3) Join()方法
Join() 称为合并线程,又称插入进程。让本线程直接到就绪状态等待CPU的调用,进而到运行状态,会让其他进程到堵塞状态。
package com.feng.state;
public class ch07_BlockedJoin01 {
public static void main(String[] args) {
Thread t = new Thread(()->{
for(int i=0;i<100;i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}) ;
t.start();
for(int i=0;i<100;i++) {
if(i%20==0) {
try {
t.join(); // 线程插队 ,,main 被阻塞了
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+i);
}
}
}
4) Yield()
Yield() 称为礼让线程,也就是让当前正在执行的线程暂停。从行状态转入就绪状态。让cpu重新调度。
它也是一个静态方法,再那里调用,哪个线程就礼让当前进程。
package com.feng.state;
public class ch05_YieldDemo01 {
public static void main(String[] args) {
new Thread(new MyYield(), "a").start();
new Thread(new MyYield(), "b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+ "-->start");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield(); // 礼让
System.out.println(Thread.currentThread().getName()+ "-->end");
}
}
5) Priority
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调 度器按照线程的优先级决定应调度哪个线程来执行。 线程的优先级用数字表示,范围从1到10
• Thread.MIN_PRIORITY = 1
• Thread.MAX_PRIORITY = 10
• Thread.NORM_PRIORITY = 5 使用下述方法获得或设置线程对象的优先级。
• int getPriority();
• void setPriority(int newPriority);
优先级的设定建议在start()调用前
注意:优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调 用优先级低的线程。
package com.feng.state;
/**
* 线程的优先级 1-10
* 1、NORM_PRIORITY 5 默认
* 2、MIN_PRIORITY 1
* 2、MAX_PRIORITY 10
* 概率 ,不代表绝对的先后顺序
*
*/
public class ch10_PriorityTest {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getPriority());
MyPriority mp = new MyPriority();
Thread t1 = new Thread(mp,"adidas");
Thread t2 = new Thread(mp,"NIKE");
Thread t3 = new Thread(mp,"回力");
Thread t4 = new Thread(mp,"李宁");
Thread t5 = new Thread(mp,"双星");
Thread t6 = new Thread(mp,"puma");
//设置优先级在启动前
t1.setPriority(10);
t2.setPriority(Thread.MAX_PRIORITY);
t3.setPriority(Thread.MAX_PRIORITY);
t4.setPriority(Thread.MIN_PRIORITY);
t5.setPriority(Thread.MIN_PRIORITY);
t6.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
Thread.yield(); // 礼让线程,将线程 返回到就绪状态。
}
}
6) Daemon()
package com.feng.state;
public class ch11_DaemonTest {
public static void main(String[] args) throws InterruptedException {
Thread t =new Thread(new God(),"God");
t.setDaemon(true);//将用户线程调整为守护
// 执行守护线程
t.start();
// 执行用户线程
Thread.sleep(Long.parseLong("1000"));
new You().start();
}
}
class You extends Thread{
@Override
public void run() {
Thread.currentThread().setName("You");
for(int i=1;i<=5;i++) {
System.out.println("happy life...");
}
System.out.println(Thread.currentThread().getName()+":finish");
}
}
class God implements Runnable{
@Override
public void run() {
for(;true;) {
System.out.println(Thread.currentThread().getName()+":bless you");
}
}
}
3. 常用其他方法
方法 | 功能 |
---|---|
isAlive() | 判断线程是否还活着,即线程是否还未终止 |
setName() | 给线程起一个名字 |
getName() | 获取线程的名字 |
currentThread() | 取得当前正在运行的线程对象,也就是获取自 己本身 |
这几个方法,上面都演示过,就不单单演示啦,都很常用。
接下来就是线程同步、线程协作:生产者消费者模式、高级主题。直接进入博客列表即可看到