五分钟带你玩转多线程(一)java多线程基础知识简介(1)

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class TestThread extends Thread{

public static void main(String [] args){

RunnableDemo test = new RunnableDemo();

test.start();

}

}

2.实现Runnable

class RunnableDemo implements Runnable {

@Override

public void run() {

for (int i = 0; i < 100; i++) {

System.out.println(“当前为” + i);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

public class TestThread extends Thread{

public static void main(String [] args){

RunnableDemo test = new RunnableDemo();

Thread t = new Thread(test);

t.start();

}

}

尽量选择runable

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立

4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类

多线程关键字使用

1

public void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

2

public void run()
如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

3

public final void setName(String name)
改变线程名称,使之与参数 name 相同。

4

public final void setPriority(int priority)
 更改线程的优先级。

5

public final void setDaemon(boolean on)
将该线程标记为守护线程或用户线程。

6

public final void join(long millisec)
等待该线程终止的时间最长为 millis 毫秒。

7

public void interrupt()
中断线程。

8

public final boolean isAlive()
测试线程是否处于活动状态。

9

public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。

10

public static void sleep(long millisec)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

11

public static boolean holdsLock(Object x)
当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。

12

public static Thread currentThread()
返回对当前正在执行的线程对象的引用。

13

public static void dumpStack()
将当前线程的堆栈跟踪打印至标准错误流。

sleep

线程睡眠的原因:线程执行的太快,或需要强制执行到下一个线程,睡眠后进入runnable中,但是睡眠完毕后不一定立即执行,需要重新争夺cpu,除非拥有更高的优先级,可以使用interrupt()方法打断,抛出InterruptedException 异常。

class RunnableDemo2 implements Runnable {

@Override

public void run() {

for (int i = 0; i < 100; i++) {

System.out.println(“当前为” + i);

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

扩展:Java线程调度是Java多线程的核心,只有良好的调度,才能充分发挥系统的性能,提高程序的执行效率。但是不管程序员怎么编写调度,只能最大限度的影响线程执行的次序,而不能做到精准控制。因为使用sleep方法之后,线程是进入阻塞状态的,只有当睡眠的时间结束,才会重新进入到就绪状态,而就绪状态进入到运行状态,是由系统控制的,我们不可能精准的去干涉它,所以如果调用Thread.sleep(1000)使得线程睡眠1秒,可能结果会大于1秒。

yield

线程让步 根据上图 可以得知 是直接进入准备状态。本线程和其他线程一样机会获取cpu资源。使用yield()的目的是让同样优先级的线程之间能适当的轮转执行。

class RunnableDemo implements Runnable {

@Override

public void run() {

for (int i = 0; i < 50; i++) {

System.out.println(Thread.currentThread().getName() + i);

if (i ==30) {

Thread.yield();

}

}

}

}

public class TestThread extends Thread{

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

RunnableDemo runnable1=new RunnableDemo();

RunnableDemo runnable2=new RunnableDemo();

Thread t1 = new Thread(runnable1,“线程1-”);

Thread t2 = new Thread(runnable1,“线程2-”);

t1.start();

t2.start();

}

}

注意:yield不会抛出异常

通过运行 我们发现 可以线程t1又抢到了资源 依然执行t1  或者t2抢到资源

join

会保证join线程完 先执行

在很多情况下,主线程生成并起动了子线程,如果子线程里要进行大量的耗时的运算,主线程往往将于子线程之前结束,但是如果主线程处理完其他的事务后,需要用到子线程的处理结果,也就是主线程需要等待子线程执行完成之后再结束,这个时候就要用到join()方法了。】

如下图 主线程在t1和t2之前完成了

class RunnableDemo implements Runnable {

@Override

public void run() {

for (int i = 0; i < 10; i++) {

System.out.println(Thread.currentThread().getName() + i);

}

}

}

public class TestThread extends Thread{

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

System.out.println(Thread.currentThread().getName()+“main开始”);

RunnableDemo runnable1=new RunnableDemo();

RunnableDemo runnable2=new RunnableDemo();

Thread t1 = new Thread(runnable1,“线程1-”);

Thread t2 = new Thread(runnable1,“线程2-”);

t1.start();

t2.start();

System.out.println(Thread.currentThread().getName()+ “main结束!”);

}

}

修改如下 可以发现主线程在最后完成

public class TestThread extends Thread{

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

System.out.println(Thread.currentThread().getName()+“main开始”);

RunnableDemo runnable1=new RunnableDemo();

RunnableDemo runnable2=new RunnableDemo();

Thread t1 = new Thread(runnable1,“线程1-”);

Thread t2 = new Thread(runnable1,“线程2-”);

t1.start();

t2.start();

t1.join();

t2.join();

System.out.println(Thread.currentThread().getName()+ “main结束!”);

}

}

其原理是:调用了先获取到子线程的锁然后调用wait方法来实现的,因为当子线程运行结束后会调用notifyall所以主线程会被唤醒并且再次获取到子线程的锁继续运行。

interrupt

https://segmentfault.com/a/1190000018191053

https://www.cnblogs.com/kaituorensheng/p/10644267.html

wait/notify/notifyall

如图,调用wait(),会使线程休眠,使该线程处于等待池(丢失锁),直到notify()/notifyAll(),会唤醒线程,线程被唤醒被放到锁定池,其他线程释放同步锁使线程回到可运行状态(Runnable)

注意:

1.Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用(在synchronized(Obj){…}语句块内).也就是wait,与notify是针对已经获取了Obj锁进行操作,并且,这三个关键字针对的是同一个监视器(某对象的监视器)。

2.因为wait之后会放开锁,所以,其他线程可以进入同步块执行。直到有其它线程调用对象的notify()唤醒该线程。才干继续获取对象锁。并继续执行。

2.notify()方法,唤醒在此对象监视器上等待的单个线程。如果多个线程在等待 那么会随机选择一个唤醒 而notifyAll()会全部唤醒

4.notify()可以唤醒wait后线程 但是实在本synchronized执行完在唤醒 唤醒后的线程和其他线程一起争夺资源

public class WaitNotify {

public static void main(String[] args) {

final Object A = new Object();

final Object B = new Object();

Thread t1 = new Thread(“t1-thread”) {

@Override

public void run() {

synchronized (A) {

System.out.println(Thread.currentThread().getName() + “拿到 A 的监视器锁”);

System.out.println(Thread.currentThread().getName() + “尝试获取 B 的监视器锁”);

try {

System.out.println(Thread.currentThread().getName() + “休眠 2s,不释放 A 的监视器锁”);

TimeUnit.SECONDS.sleep(2);

System.out.println(Thread.currentThread().getName() + “挂起自己,释放 A 的监视器锁”);

A.wait();

System.out.println(Thread.currentThread().getName() + “被唤醒,等待获取 B 的监视器锁”);

} catch (InterruptedException e) {

e.printStackTrace();

}

synchronized (B) {

System.out.println(Thread.currentThread().getName() + “拿到 B 的监视器锁”);

B.notify();

}

}

}

};

Thread t2 = new Thread(“t2-thread”) {

@Override

public void run() {

synchronized (B) {

System.out.println(Thread.currentThread().getName() + “拿到 B 的监视器锁”);

System.out.println(Thread.currentThread().getName() + “尝试获取 A 的监视器锁”);

synchronized (A) {

System.out.println(Thread.currentThread().getName() + “拿到 A 的监视器锁”);

try {

System.out.println(Thread.currentThread().getName() + “休眠 2s,不释放 A 的监视器锁”);

TimeUnit.SECONDS.sleep(2);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + “挂起自己,释放 A 的监视器锁,唤醒 t0”);

A.notify();

}

try {

System.out.println(Thread.currentThread().getName() + “休眠 2s,不释放 B 的监视器锁”);

TimeUnit.SECONDS.sleep(2);

System.out.println(Thread.currentThread().getName() + “挂起自己,释放 B 的监视器锁”);

B.wait();

System.out.println(Thread.currentThread().getName() + “被唤醒”);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

};

t1.start();

t2.start();

}

}

t2-thread拿到 B 的监视器锁

t2-thread尝试获取 A 的监视器锁

t1-thread拿到 A 的监视器锁

t1-thread尝试获取 B 的监视器锁

t1-thread休眠 2s,不释放 A 的监视器锁

t1-thread挂起自己,释放 A 的监视器锁

t2-thread拿到 A 的监视器锁

t2-thread休眠 2s,不释放 A 的监视器锁

t2-thread挂起自己,释放 A 的监视器锁,唤醒 t0

t2-thread休眠 2s,不释放 B 的监视器锁

t1-thread被唤醒,等待获取 B 的监视器锁

t2-thread挂起自己,释放 B 的监视器锁

t1-thread拿到 B 的监视器锁

t2-thread被唤醒

优先级


static int MAX_PRIORITY:线程可以具有的最高优先级,取值为10。

static int MIN_PRIORITY: 线程可以具有的最低优先级,取值为1。

static int NORM_PRIORITY: 分配给线程的默认优先级,取值为5,主线程默认的优先级。

t.setPriority(1); 设置优先级 数字越高 先执行线程的机会越多

public class TestThread extends Thread{

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

RunnableDemo test1 = new RunnableDemo();

Thread t = new Thread(test1,“线程1-”);

Thread t2 = new Thread(test1,“线程2-”);

Thread t3 = new Thread(test1,“线程3-”);

t.setPriority(1);

t2.setPriority(8);

t3.setPriority(9);

t.start();

t2.start();

t3.start();

}

}

同步

线程安全问题:多个线程同时进行,会发现与单线程运行结果不同(经典的卖票问题)

class RunnableDemo implements Runnable {

int x = 10;

@Override

public void run() {

while (x>0){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

–x;

System.out.println(Thread.currentThread().getName() + x);

}

}

}

public class TestThread extends Thread{

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

RunnableDemo test1 = new RunnableDemo();

Thread t = new Thread(test1,“线程1-”);

Thread t2 = new Thread(test1,“线程2-”);

Thread t3 = new Thread(test1,“线程3-”);

t.start();

t2.start();

t3.start();

}

}

处理办法1:synchronized关键字 会保证当前只有一个线程调用 但是运行效率会变低

class RunnableDemo implements Runnable {

int x = 10;

@Override

public synchronized void run() {

while (x>0){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

–x;

System.out.println(Thread.currentThread().getName() + x);

}

}

}

处理办法2

class RunnableDemo implements Runnable {

private Lock lock = new ReentrantLock();

int x = 10;

@Override

public void run() {

lock.lock(); //上锁

try {

while (x>0){

try {

Thread.sleep(10);

} catch (InterruptedException e) {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

在这里插入图片描述

最新整理电子书

在这里插入图片描述

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
存中…(img-oqhpik12-1713570711303)]

[外链图片转存中…(img-H92BzuSZ-1713570711304)]

[外链图片转存中…(img-nroeomoT-1713570711306)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

针对最近很多人都在面试,我这边也整理了相当多的面试专题资料,也有其他大厂的面经。希望可以帮助到大家。

下面的面试题答案都整理成文档笔记。也还整理了一些面试资料&最新2021收集的一些大厂的面试真题(都整理成文档,小部分截图)

[外链图片转存中…(img-rZ8mlCYj-1713570711307)]

最新整理电子书

[外链图片转存中…(img-v7pywvto-1713570711308)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 23
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值