java多线程学习一、线程介绍、线程创建的3种方式、lambda创建方式、线程状态、线程示例:12306买票和银行取钱
文章目录
- 前言
- 一、线程简介
- 1.概述
- 2.进程、线程 区别
- 在这里插入图片描述
- 3. 核心概念
- 二、 线程创建
- 1.概述
- 2. 第一种方式继承Thread
- 1) 继承Thread
- 2) 示例:下载图片
- 3. 第二种方式:实现Runnable
- 5. 第三种方式:实现Callable
- 5. Thread对比Runnable
- 6. 线程示例
- 1) 龟兔赛跑
- 2) 12306购票
- 三、静态代理和动态代理
- 1. 静态代理
- 1) 概述
- 2) 示例
- 2. 动态代理
- 1) 概述
- 2) 示例
- 四、 lambda表达式创建进程
- 五、 线程状态
- 1. 概述
- 2. 线程方法
- 1) 线程停止
- 2) Sleep()
- a) 示例1 模拟12306 抢票
- 3) Join()方法
- 4) Yield()
- 5) Priority
- 6) Daemon()
- 3. 常用其他方法
前言
之前在学校学习线程,就是很简单的学习创建和使用,一般也没用过线程,因为在学校根本用不到并发。线程的好处有很多:提高资源利用率,让电脑的资源充分利用起来;可以提高程序的运行速度;等等。
在公司,一般都会用到线程开发,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 {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic 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> {@Overridepublic 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;// 胜利者@Overridepublic 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;@Overridepublic 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 {@Overridepublic void action() {System.out.println("喵喵喵~~~~~~~");}@Overridepublic 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;}@Overridepublic void action() {System.out.println("==========catProxy 代理类执行开始!=============");//实质上在代理类中是调用了被代理实现接口的方法cat.action();System.out.println("==========catProxy 代理类执行结束!===========");}@Overridepublic 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 {@Overridepublic void action() {System.out.println("汪汪汪~~~~~~~");}@Overridepublic 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;}@Overridepublic void action() {System.out.println("==========dogProxy 代理类执行开始!=============");//实质上在代理类中是调用了被代理实现接口的方法dog.action();System.out.println("==========dogProxy 代理类执行结束!===========");}@Overridepublic 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 {@Overridepublic void action() {System.out.println("喵喵喵~~~~");}@Overridepublic void breath() {System.out.println("猫式呼吸法~~~~");}
}
Dog.java
package com.feng.springboottest.other.staticproxy.dynamicproxy;public class Dog implements Animal {@Overridepublic void action() {System.out.println("汪汪汪~~~~~");}@Overridepublic 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*/@Overridepublic 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{@Overridepublic void run() {System.out.println("一边听歌");}}public static void main(String[] args) {new Thread(new Test01()).start();//第二次简化:局部内部类class Test02 implements Runnable{@Overridepublic void run() {System.out.println("一边看书");}}new Thread(new Test02()).start();// 第三次简化: 匿名内部类, 必须借助接口或者父类new Thread(new Runnable() {@Overridepublic 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;}@Overridepublic 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;@Overridepublic 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{@Overridepublic 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{@Overridepublic 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{@Overridepublic 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{@Overridepublic void run() {for(;true;) {System.out.println(Thread.currentThread().getName()+":bless you");}}
}
3. 常用其他方法
方法 | 功能 |
---|---|
isAlive() | 判断线程是否还活着,即线程是否还未终止 |
setName() | 给线程起一个名字 |
getName() | 获取线程的名字 |
currentThread() | 取得当前正在运行的线程对象,也就是获取自 己本身 |
这几个方法,上面都演示过,就不单单演示啦,都很常用。
接下来就是线程同步、线程协作:生产者消费者模式、高级主题。直接进入博客列表即可看到
java多线程学习一、线程介绍、线程创建的3种方式、lambda创建方式、线程状态、线程示例:12306买票和银行取钱相关推荐
- java多线程学习二、安全与不安全示例:12306买票和银行取钱、java内存模型、内存可见性、线程同步块和方法
文章目录 前言 1. 什么是块,分为几种 2. 静态块与构造块的区别 一. 举例说明:并发情况下,线程不安全 1. 示例1:unsafe12306取票 2. 示例2:unsafe银行取钱 二.线程不安 ...
- java线程学习,GitHub - zksir/thread: Java多线程学习
Java多线程学习 threadcoreknowledge包----线程核心知识基础 createthreads包 创建线程 1.实现多线程的方法是1种还是2种还是4种? Oracle官方:2种,一种 ...
- Java多线程学习处理高并发问题
在程序的应用程序中,用户或请求的数量达到一定数量,并且无法避免并发请求.由于对接口的每次调用都必须在返回时终止,因此,如果接口的业务相对复杂,则可能会有多个用户.调用接口时,该用户将冻结. 以下内容将 ...
- java多线程学习-java.util.concurrent详解
http://janeky.iteye.com/category/124727 java多线程学习-java.util.concurrent详解(一) Latch/Barrier 博客分类: java ...
- Java多线程学习(二)synchronized关键字(1)
转载请备注地址: https://blog.csdn.net/qq_34337272/article/details/79655194 Java多线程学习(二)将分为两篇文章介绍synchronize ...
- java多线程学习笔记。
java多线程学习笔记 线程的优缺点: 多线程的好处: 充分利用多处理核心,提高资源的利用率和吞吐量. 提高接口的响应效率,异步系统工作. 线程的风险: 安全危险(竞争条件):什么坏事都没有发生.在没 ...
- 【转】Java 多线程学习
原网址:https://www.cnblogs.com/yjd_hycf_space/p/7526608.html Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实J ...
- 转:Java多线程学习(总结很详细!!!)
Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程 ...
- Java多线程学习——01
Java多线程学习--01 1.核心概念 程序:是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念 进程Process:是执行程序的一次执行过程,它是一个动态的概念,是系统资源分配的单 ...
最新文章
- ValueTransformer
- 对信噪比SNR、EbN0、EsN0的个人详细理解
- GIS实战应用案例100篇(二)-元胞自动机模拟城市扩张过程
- php string slice,substring()与str.slice()区别
- css中hover的妙用!!
- 机器学习_贝叶斯算法
- PN序列的产生以及相关函数的计算
- 微信小程序弹框种类汇总
- 我的Windows Server 2008激活
- EXCEL功能之Excel表格边框设置
- 移动硬盘插入电脑后不显示盘符
- 【OpenGL】用GLFW和glad创建窗口
- 物理量与单位符号的书写标准
- 2022-2028年中国中频加热设备行业市场发展调研及未来前景规划报告
- 如何做IT项目PoC测试
- python求逆矩阵的方法,Python 如何求矩阵的逆
- 停车场web项目(内含有数据库)
- Ectiture impossible,doublon dans une cle de la错误
- Ribbon与Hystrix
- (原创)使用AsyncTask(带修改线程池方式)+自定义ImageLoader+LRU算法对图片三级缓存及其显示优化(只有在ListView滑动停止的时候才去网络请求获取图片数据)