Java的多线程1:线程的使用
Java的多线程1:线程的使用
概述
进程是线程的容器,线程共享进程的内存空间,所以线程之间彼此通信是比较容易的,而线程又有自己私有的内存地址,其他线程无法访问。了解进程和线程关系,可以看我另一篇博客《进程与线程》
Java创建线程的两种方式
继承Thread类
public class ThreadDemo1 extends Thread {
@Override public void run(){ for (int i = 0; i < 10; i++) { System.out.println("当前执行的线程是" + Thread.currentThread().getName()); } } public static void main(String[] args) { ThreadDemo1 threadDemo1 = new ThreadDemo1(); ThreadDemo1 threadDemo2 = new ThreadDemo1(); threadDemo1.start(); threadDemo2.start(); }
}
执行结果是不确定的
实现Runnable
public class ThreadDemo2 implements Runnable {
@Override public void run() { for (int i = 0; i < 10; i++) { for (int j = 0;j < 1000; ++j){ System.out.println(i + "当前执行的线程是" + Thread.currentThread().getName()); } } } public static void main(String[] args) { ThreadDemo2 threadDemo1 = new ThreadDemo2(); ThreadDemo2 threadDemo2 = new ThreadDemo2(); Thread thread1 = new Thread(threadDemo1); Thread thread2 = new Thread(threadDemo2); thread1.start(); thread2.start(); System.out.println("当前线程是===>" + Thread.currentThread().getName()); }
}
主线程的名字为main,非主线程的名字是由虚拟机来指定的,同时,我们也可以为线程指定具体的名称。
我们保证每个线程都能正常启动,并不意味着它会按顺序的执行,因为调度程序是无法保证它的执行次序的,同时,run()函数结束时,意味着该线程的任务完成了。
注意:调用线程要调用start,如果调用run,那仅仅是简单的对象调用。
线程生命周期
public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }
新建状态
线程对象创建后,就进入新建状态 Thread thread = new Thread
就绪状态
调用start()方法,线程进入就绪状态,但并不意味着线程就立即执行,只是说明此线程已经做好准备,随时等待CPU调度执行。
阻塞状态
多个线程同时竞争一个独占锁,其他未抢到锁的线程,就进入阻塞状态被放置到锁池中,直到获取到锁,进入就绪状态
等待状态
该线程需要等待其他线程做出一些特定动作,通知或者是中断,等待其被其他线程唤醒,像CountDownLatch就可以等待一个或者几个线程结束。
超时等待状态
和等待状态不同的是,它可以在指定的时间自行的返回,sheep(long)函数就会让线程进入超时等待状态,时间到了才会转入就绪状态。
运行状态(Running)
CPU调度处于就绪状态的线程时,这个线程才真正执行,进入运行状态。
终止状态
线程正常执行完毕后或提前强制性终止或出现异常,线程就要销毁,释放资源。
线程的方法调用
获取线程基本信息
public class ThreadDemo6 {
public static void main(String[] args) { Thread thread = new Thread(){ @Override public void run(){ /*获取线程唯一id标识*/ long id = this.getId(); System.out.println("thread的ID==>" + id); /*获取线程名字*/ String name = this.getName(); System.out.println("thread的名字==>" + name); /*获取线程的优先级 默认5 1-10*/ int priority = this.getPriority(); System.out.println("thread的优先等级==>" + priority); /*查看当前线程是否为守护线程*/ boolean isDaemon = this.isDaemon(); System.out.println("thread是否为守护线程==>" + isDaemon); /*查看线程是否被中断*/ boolean isInterrupted = this.isInterrupted(); System.out.println("thread是否被中断==>" + isInterrupted); } }; thread.start(); }
}
执行结果
thread的ID==>11
thread的名字==>Thread-0
thread的优先等级==>5
thread是否为守护线程==>false
thread是否被中断==>false
Thread.yield()
public class ThreadDemo1 implements Runnable {
protected int countDown = 10; private static int taskCount = 0; private final int id = taskCount++; public ThreadDemo1(){} public ThreadDemo1(int countDown){ this.countDown = countDown; } public String status(){ return "#" + id + "(" + (countDown > 0 ? countDown : "stop!") + ")"; }
@Override public void run() { while (countDown-- > 0){ System.out.println(status() + " "); Thread.yield(); } } public static void main(String[] args) { for (int i = 0; i < 3; i++){ new Thread(new ThreadDemo1()).start(); } }
}
0(9)#0(8)#0(7)#0(6)#0(5)#0(4)#0(3)#0(2)#0(1)#0(stop!)
1(9)#1(8)#1(7)#1(6)#1(5)#1(4)#1(3)#1(2)#1(1)#1(stop!)
2(9)#2(8)#2(7)#2(6)#2(5)#2(4)#2(3)#2(2)#2(1)#2(stop!)
这个是一个倒计时的任务,对Thread.yield()调用是对线程调度器的一种建议,它在声明“我已经执行完生命周期中最重要的部分了,此刻正是切换给其他任务执行一段时间的大好时机”,说白就是自己按暂停键,让出自己CPU的使用权限,转为就绪状态,至于下一次什么时候能获得CPU调度就不一定了,有时很快,有时得等上一会。
Thread.sleep
public class ThreadDemo1 implements Runnable {
protected int countDown = 10; private static int taskCount = 0; private final int id = taskCount++; public ThreadDemo1(){} public ThreadDemo1(int countDown){ this.countDown = countDown; } public String status(){ return "#" + id + "(" + (countDown > 0 ? countDown : "stop!") + ")"; }
@Override public void run() { try { while (countDown-- > 0){ System.out.println(status()); Thread.sleep(1000); } } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { for (int i = 0; i < 3; i++){ new Thread(new ThreadDemo1()).start(); } }
}
Thread.sleep(long)将使“正在执行的任务“中止执行给定的时间(暂停执行)并且让出CPU使用权,这个语句相当于说在接下来的1秒内,你都不要叫我,我想睡一会,1秒睡眠时间过后,它自动转为就绪状态,但CPU不一定马上执行这个睡醒的线程,这要取决于是否抢到CPU时间片段。值得注意的是如果sleep和yield上下文被加锁了,它们依然使用锁,不会去释放。而sleep与yield最大的不同是,yield不会让线程进入等待状态,只是把线程转为就绪状态,并把CPU执行机会让步给优先级相同或者更高的线程,而sleep能控制具体交出CPU的使用时间。
Thread.currentThread()
public class ThreadDemo2 extends Thread {
static { System.out.println("静态块执行的线程===>" + Thread.currentThread().getName()); } { System.out.println("非静态块执行的线程是====>" + Thread.currentThread().getName()); System.out.println("this.getName()1=====>" + this.getName()); } public ThreadDemo2(){ System.out.println("构造方法内执行的线程====>" + Thread.currentThread().getName()); System.out.println("this.getName()2=====>" + this.getName()); } @Override public void run() { System.out.println("当前执行的线程为====>" + Thread.currentThread().getName()); System.out.println("this.getName()3=====>" + this.getName()); } public static void main(String[] args) { ThreadDemo2 threadDemo2 = new ThreadDemo2(); threadDemo2.start(); }
}
执行结果
静态块执行的线程===>main
非静态块执行的线程是====>main
this.getName()1=====>Thread-0
构造方法内执行的线程====>main
this.getName()2=====>Thread-0
当前执行的线程为====>Thread-0
this.getName()3=====>Thread-0
currentThread返回的是当前正在执行线程对象的引用,它与this.getName()有明显的不同,执行静态块,非静态块,构造方法的线程是main,而非ThreadDemo2,在执行run()方法的才是实例化的线程threadDemo2。所以在当前执行的Thread未必就是Thread本身。
isAlive()
public class ThreadDemo3 extends Thread {
@Override public void run(){ System.out.println("执行执行====" + this.isAlive()); } public static void main(String[] args) { ThreadDemo3 threadDemo3 = new ThreadDemo3(); System.out.println("begin===>" + threadDemo3.isAlive()); threadDemo3.start(); System.out.println("end==>" + threadDemo3.isAlive()); }
}
begin===>false
end==>true
执行执行====true
isAlive()检测线程是否处于活动状态,活动状态返回true
setPriority()
优先级设定,优先级高的线程越容易获取CPU使用权,
public class ThreadDemo4 {
public static void main(String[] args) { for (int i = 0; i < 5; ++i){ Thread1 thread1 = new Thread1(); thread1.setPriority(6); Thread2 thread2 = new Thread2(); thread2.setPriority(4); thread2.start(); thread1.start(); } }
}
class Thread1 extends Thread{
@Override public void run(){ for (int i = 0; i < 100000; ++i){ System.out.println("+++++++++++++"); } }
}
class Thread2 extends Thread{
@Override public void run(){ for (int i = 0; i < 100000; ++i){ System.out.println("--------------"); } }
}
执行结果
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
+++++++++++++
...
CPU会将资源尽量让给优先级高的线程
setDaemon()
守护线程,也有人叫后天线程,我们创建出来的线程默认都是前台线程,在使用上来说,守护线程和前台线程是没啥区别,区别在于进程结束,当一个进程中的所有前台线程都结束时,无论这个进程中的守护线程是否还在运行都要强制将他们结束。也就是说前台线程都结束了,守护线程也会自动销毁,它是为其他线程提供便利而存在的。
/rose与jack/
public class ThreadDemo5 {
public static void main(String[] args) { Rose rose = new Rose(); Jack jack = new Jack(); /*设置为守护线程必须在线程未启动之前*/ jack.setDaemon(true); rose.start(); jack.start(); }
}
class Rose extends Thread{
@Override public void run(){ for (int i = 0; i < 5; ++i){ System.out.println("rose: let me go!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("成功跳水"); }
}
class Jack extends Thread{
@Override public void run(){ while (true){ System.out.println("jack:you jump! i jump!"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }
}
执行结果
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
rose: let me go!
jack:you jump! i jump!
成功跳水
jack守护着rose,jack是守护线程,当rose跳水后,jack认为自己也没有活着的必要了,也自己销毁了,但注意一点是这当中还有一个第三者main,需要main也运行完jack线程才会销毁。
join()
这个方法可以协调多个线程同步运行,多线程运行本身是设计异步运行的,但在程序运行业务中,有可能线程A的计算需要线程B的返回结果,这就需要他们执行各自任务时要有先后,join就需要协调这些线程同步运行。
public class ThreadDemo6 {
private static boolean isFinish = false; public static void main(String[] args) { Thread download = new Thread(){ @Override public void run(){ System.out.println("下载图片中....."); for (int i = 1; i <= 100; ++i){ System.out.println("下载进度" + i + "%"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("图片下载完毕"); isFinish = true; } }; Thread show = new Thread(){ @Override public void run(){ System.out.println("开始显示图片..."); try { download.join(); } catch (InterruptedException e) { e.printStackTrace(); } if (!isFinish){ throw new RuntimeException("图片下载出错"); } System.out.println("图片正常展示。。。"); } }; download.start(); show.start(); }
}
执行结果
下载图片中.....
开始显示图片...
下载进度1%
下载进度2%
...
下载进度100%
图片下载完毕
图片正常展示。。。
show调用join会使show无限阻塞,直到down线程销毁为止,它和sleep最大的区别是join会释放锁,而sleep不会。
涉及到jmm内存模型,线程安全等,后面在介绍
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
记一次JAVA进程导致Kubernetes节点CPU飙高的排查与解决
记一次JAVA进程导致Kubernetes节点CPU飙高的排查与解决 一、发现问题在一次系统上线后,我们发现某几个节点在长时间运行后会出现CPU持续飙升的问题,导致的结果就是Kubernetes集群的这个节点会把所在的Pod进行驱逐(调度);如果调度到同样问题的节点上,也会出现Pod一直起不来的问题。我们尝试了杀死Pod后手动调度的办法(label),当然也可以排除调度节点。但是在一段时间后还会复现,我们通过监控系统也排查了这段时间的流量情况,但应该和CPU持续占用没有关联,这时我们意识到这可能是程序的问题。 二、排查问题定位Pod这里使用kubectl top pods 命令确定CPU占用最高的pods都是哪些。 kubectl -n app top pods 因为问题已解决,以上图片只是举个例子。 排查工具Arthas我们这边使用了阿里的Arthas ,它是Alibaba开源的Java诊断工具。当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 我改的代码为什么没有执行到?难道是我没 comm...
- 下一篇
Java 中的递归
Java 中的递归 递归递归一种通过调用某个方法来描述需要重复进行的操作。该方法的特点就是可以自己调用自己。 案例一排队的问题在生活中,我们经常需要排队。在排队中,我们怎么才能知道自己所排在第几位呢? 我们也许会想到数自己前面有几个人,这就是典型的迭代思想。就像是一个while循环,只要前面还有没数过的人,就不会停止。这种方式相对来说是比较直观的,但是同样也有局限性。比如在排队时,遇到了转弯,我们看不到前面的人怎么办呢? 有一个方法,我们可以通过询问前面一个人他所处的位置。假设有A、B、C、D四个人,D询问C所在的位置,C询问B所在位置,B询问A所在的位置。A知道自己排在第一位(他不需要再问别人了,这一个询问的过程结束),然后告诉B,那B就知道自己在第二位;然后B告诉C,C也就知道了自己在第三位;最后C告诉D他在第三位时,D也就知道自己所在的位置了。这就是使用递归思想来分析问题——每个人都来回答一个问题,从而使这个问题多次重现(recur)。 这一点也是递归思想的精髓所在,递归方法涉及多个进行合作的单元,每个单元负责解决问题的一小部分。例如刚刚那个例子,每个人都像前询问一个问题,最后每...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS关闭SELinux安全模块
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装