Java中的线程基础

  • 下面内容是我根据B站视频总结,这是线程的基础部分的,如果有错误,欢迎指正 *

概念

  • 进程:我们编写的代码只是一个存储在硬盘的静态文件,通过编译后就会生成二进制可执行文件,当我们运行这个可执行文件后,它会被装载到内存中,接着 CPU 会执行程序中的每一条指令,那么这个运行中的程序,就被称为「进程」(Process)。
  • 进程是程序的一次执行过程,或者正在运行的一个程序,是动态的过程,有它自身的产生、存在和消亡的过程
  • 线程是由进程创建的,是进程一个实体
  • 一个进程可以拥有多个线程
  • 单线程:同一时刻,只允许执行一个线程;多线程:同一个时刻,可以执行多个线程
  • 并发:同一时刻,多任务交替执行,造成一种貌似同时的错觉,简单的说,单核cpu实现的多任务就是并发
  • 并行:同一时刻,多个任务同时执行,多核cpu可以实现并行

线程的基本使用

1、创建线程的2种方式

  • 继承Thread类,重写run方法
  • 实现Runnable接口,重写run方法
    2、当一个类继承类Thread类,该类就可以当做线程使用
    3、我们会重写run方法,写上自己的业务代码
    4、run Thread类实现了Runnable接口的run方法

继承Thread类

底层机制

// start0()是本地方法,是JVM调用,底层是c/c++实现
// 真正实现多线程的效果,是start0()而不是run
// start()方法调用start0()方法后,该线程并不一定会立马执行,只是将线程变成了可运行状态,具体什么时候执行,取决于CPU,由CPU统一调度
(1)
public synchronized void start() {
	start0();
}
(2)
private native void start0();

例如:

package thread_use;

public class Thread_01 {
    public static void main(String[] args) {
        //创建一个Dog对象可以当作线程使用
        Child_Thread child_thread = new Child_Thread();
        //启动线程,最终会执行Child_Thread的run方法
        child_thread.start();
        // 当main线程启动一个子线程Thread-0,主线程不会阻塞,会继续执行
        // 主线程和子线程是交替执行

        // child_thread.run(); // 这里就是main线程的普通方法。没有真正的启动一个线程,把这个run方法执行完毕,才会往下执行

        for (int i=0;i<5;i++){
            System.out.println("主线程 "+i+" 线程名:"+Thread.currentThread().getName());
            //让主线程休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

class Child_Thread extends Thread{
    int num=0;
    @Override
    public void run() {
        while (true) {
            System.out.println("子线程 "+(num++)+" 线程名:"+Thread.currentThread().getName());
            //让该线程休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (num==5){
                break;  //当num等于5就退出
            }
        }
    }
}

输出结果:

主线程 0 线程名:main
子线程 0 线程名:Thread-0
主线程 1 线程名:main
子线程 1 线程名:Thread-0
主线程 2 线程名:main
子线程 2 线程名:Thread-0
主线程 3 线程名:main
子线程 3 线程名:Thread-0
主线程 4 线程名:main
子线程 4 线程名:Thread-0**

实现Runnable接口

1、java是单继承,在某些情况下一个类可能已经继承了某个父类,这时用继承Thread类的方法来创建线程显然不可能了
2、java设计者提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程

例如:

package thread_use;

public class Thread_03 {
    public static void main(String[] args) {
        Child_Thread01 childThread01 = new Child_Thread01();
        // childThread01.start(); 这里不能调用start
        //创建了Thread对象,把childThread01对象(实现Runnable)放入Thread
        Thread thread = new Thread(childThread01);
        thread.start();

    }
}
class Child_Thread01 implements Runnable{
    int num=0;
    @Override
    public void run() {
        while (true){
            System.out.println("子线程 "+(num++)+" 线程名:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (num==10){
                break;
            }
        }
    }
}

输出结果:

子线程 0 线程名:Thread-0
子线程 1 线程名:Thread-0
子线程 2 线程名:Thread-0
子线程 3 线程名:Thread-0
子线程 4 线程名:Thread-0
子线程 5 线程名:Thread-0
子线程 6 线程名:Thread-0
子线程 7 线程名:Thread-0
子线程 8 线程名:Thread-0
子线程 9 线程名:Thread-0

例如:

package thread_use;

public class Thread_02 {
    public static void main(String[] args) {
        Child child = new Child();
        ThreadProxy threadProxy = new ThreadProxy(child);
        threadProxy.start();
    }
}

class People{}
class Child extends People implements Runnable{

    @Override
    public void run() {
        System.out.println("Child_Thread");
    }
}

//线程代理类,模拟一个最简单的Thread类
class ThreadProxy implements Runnable{
    private Runnable target =null; //属性,类型是Runnable

    public ThreadProxy(Runnable target) {
        this.target = target;
    }

    public void start(){
        start0();
    }
    public void start0(){
        run();
    }

    @Override
    public void run() {
        if (target != null){
            target.run(); //动态绑定
        }
    }
}

输出结果:

Child_Thread

多个子线程

例如:

package thread_use;

public class Thread_04 {
    public static void main(String[] args) {
        Th1 th1 = new Th1();
        Th2 th2 = new Th2();
        Thread thread1 = new Thread(th1);
        Thread thread2 = new Thread(th2);
        thread1.start(); //启动第一个线程
        thread2.start(); //启动第二个线程
        System.out.println("主线程结束");
    }
}

class Th1 implements Runnable{
    int num=0;
    @Override
    public void run() {
        while(true) {
            System.out.println("子线程1--" + (num++) + " 线程名:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (num == 5) {
                break;
            }
        }
    }
}
class Th2 implements Runnable{
    int num=0;
    @Override
    public void run() {
        while(true) {
            System.out.println("子线程2--" + (num++) + " 线程名:" + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (num == 5) {
                break;
            }
        }
    }
}

输出结果:

主线程结束
子线程2--0 线程名:Thread-1
子线程1--0 线程名:Thread-0
子线程1--1 线程名:Thread-0
子线程2--1 线程名:Thread-1
子线程1--2 线程名:Thread-0
子线程2--2 线程名:Thread-1
子线程1--3 线程名:Thread-0
子线程2--3 线程名:Thread-1
子线程1--4 线程名:Thread-0
子线程2--4 线程名:Thread-1

继承Thread vs 实现Runnable

1、从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别,Thread类本身就实现了Runnable接口
2、实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制

例如:

package thread_use;

public class thread_05 {
    public static void main(String[] args) {
        SellTicket sellTicket1 = new SellTicket();
        SellTicket sellTicket2 = new SellTicket();
        SellTicket sellTicket3 = new SellTicket();
        //出现票数超卖的问题
        sellTicket1.start();
        sellTicket2.start();
        sellTicket3.start();
    }
}

class SellTicket extends Thread{
    private static int ticket_num=5;

    @Override
    public void run() {
        while(true){
            if (ticket_num<=0){
                System.out.println("售票结束...");
                break;
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口:"+Thread.currentThread().getName()+" 还剩:"+(--ticket_num)+"张票");

        }
    }
}

输出结果:

窗口:Thread-1 还剩:4张票
窗口:Thread-0 还剩:3张票
窗口:Thread-2 还剩:2张票
窗口:Thread-0 还剩:1张票
窗口:Thread-1 还剩:0张票
售票结束...
窗口:Thread-2 还剩:-1张票
售票结束...
窗口:Thread-0 还剩:-2张票
售票结束...

例如:

package thread_use;

public class Thread_06 {
    public static void main(String[] args) {
        SellTicket1 sellTicket1 = new SellTicket1();

        Thread thread1 = new Thread(sellTicket1);
        Thread thread2 = new Thread(sellTicket1);
        Thread thread3 = new Thread(sellTicket1);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class SellTicket1 implements Runnable{
    private static int ticket_num=5;

    @Override
    public void run() {
        while(true){
            if (ticket_num<=0){
                System.out.println("售票结束...");
                break;
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口:"+Thread.currentThread().getName()+" 还剩:"+(--ticket_num)+"张票");
        }
    }
}

输出结果:

窗口:Thread-1 还剩:4张票
窗口:Thread-0 还剩:3张票
窗口:Thread-2 还剩:2张票
窗口:Thread-1 还剩:1张票
窗口:Thread-0 还剩:1张票
售票结束...
窗口:Thread-2 还剩:0张票
售票结束...
售票结束...

线程终止

1、当线程完成任务后,会自动退出
2、还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式
例如:

package thread_use;

public class Thread_07 {
    public static void main(String[] args) {
        AA aa = new AA();
        aa.start();

        //如果希望main线程去控制aa线程终止,必须可以修改loop
        //让aa退出run方法,从而终止aa线程,称为:通知方式
        System.out.println("主线程休眠");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        aa.setLoop(false);
    }
}

class AA extends Thread{
    private int num=0;
    private boolean loop=true;
    @Override
    public void run() {
        while (loop){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("子线程运行中 "+(num++));
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}

输出结果:

主线程休眠
子线程运行中 0
子线程运行中 1
子线程运行中 2
子线程运行中 3
子线程运行中 4

线程常用方法

1、setName:设置线程名称,使之与参数name相同
2、getName:返回该线程的名称
3、start:使该线程开始执行;java虚拟机底层调用该线程的start0方法
4、run:调用线程对象run方法
5、setPriority:更改线程优先级
6、getPriority:获取线程优先级
7、sleep:在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
8、interrupt:中断线程

注意
1、start底层会创建新的线程,调用runrun就是一个简单的方法调用,不会启动新线程
2、线程优先级的范围,常用的有:

  • MAX_PRIORITY : 10
  • MIN_PRIORITY : 1
  • NORM_PRIORITY : 5

3、interrupt,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠的线程
4、sleep 线程的静态方法,使当前的线程休眠

例如:

package thread_use;

public class Thread_08 {
    public static void main(String[] args) {
        T t = new T();
        t.setName("sls");
        t.setPriority(Thread.MIN_PRIORITY);
        t.start();

        //主线程循环,之后中断子线程休眠
        for (int i=0;i<10;i++){
            try {
                Thread.sleep(1000);
                System.out.println("主线程 "+i);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        t.interrupt();

    }
}

class T extends Thread{
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            //Thread.currentThread().getName() 获取当前线程名称
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            //InterruptedException捕获一个中断异常
            //当该线程执行到一个interrupt方法时,就会catch一个异常,可以加入自己的业务代码中
            System.out.println(Thread.currentThread().getName()+" 中断结束");
        }
    }
}

输出结果:

sls 0
sls 1
sls 2
sls 3
sls 4
sls 5
sls 6
sls 7
sls 8
sls 9
sls
主线程 0
主线程 1
主线程 2
主线程 3
主线程 4
主线程 5
主线程 6
主线程 7
主线程 8
主线程 9
sls 中断结束

此外
1、yield:线程的礼让,让出CPU,让其他线程执行,但礼让的时间不确定,所以不一定礼让成功
2、join:线程的插队。插队的线程一旦成功,这肯定先执行完插入的线程所有的任务
例如:

package thread_use;

public class Thread_09 {
    public static void main(String[] args) throws InterruptedException{
        TT tt = new TT();
        tt.start();
        for (int i=1;i<5;i++){
            Thread.sleep(2000);
            System.out.println("主线程 "+i);
            if(i==3){
                System.out.println("主线程礼让子线程");
                tt.join();
                System.out.println("子线程结束,主线程运行");
            }
        }
    }
}

class TT extends Thread{
    @Override
    public void run() {
        for (int i=0;i<5;i++){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("子线程 "+i );
        }
    }
}

输出结果:

主线程 1
子线程 0
主线程 2
子线程 1
主线程 3
主线程礼让子线程
子线程 2
子线程 3
子线程 4
子线程结束,主线程运行
主线程 4

用户线程和守护线程

1、用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
2、守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
3、常见的守护线程:垃圾回收机制
例如:

package thread_use;

public class Thread_10 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        //如果希望主线程结束子线程也结束,只需将子线程设置成守护线程
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();

        for (int i=0;i<5;i++){
            Thread.sleep(1000);
            System.out.println("主线程 "+i);
        }
    }
}

class MyDaemonThread extends Thread{
    @Override
    public void run() {
        for (; ; ){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("子线程");
        }
    }
}

输出结果:

子线程
主线程 0
子线程
主线程 1
子线程
主线程 2
子线程
主线程 3
子线程
主线程 4

线程的生命周期

线程可以处于一下状态之一:

  • NEW:尚未启动的线程处于此状态
  • RUNNABLE:在java虚拟机中执行的线程处于此状态
  • BLOCKED:被阻塞等待监视器锁定的线程处于此状态
  • TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
  • TERMINATED:已退出的线程处于此状态
  • 在这里插入图片描述
    例如:
package thread_use;

public class Thread_11 {
    public static void main(String[] args) {
        T1 t1 = new T1();
        System.out.println("线程名: "+t1.getName()+"线程状态:"+t1.getState());
        t1.start();
        while(t1.getState()!=Thread.State.TERMINATED){
            System.out.println("线程名: "+t1.getName()+"线程状态:"+t1.getState());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("线程名: "+t1.getName()+"线程状态:"+t1.getState());

    }
}

class T1 extends Thread{
    @Override
    public void run() {
        for (int i=0;i<5;i++ ){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("子线程("+Thread.currentThread().getName() +")运行中");
        }
    }
}

输出结果:

线程名: Thread-0线程状态:NEW
线程名: Thread-0线程状态:RUNNABLE
线程名: Thread-0线程状态:TIMED_WAITING
子线程(Thread-0)运行中
线程名: Thread-0线程状态:TIMED_WAITING
子线程(Thread-0)运行中
子线程(Thread-0)运行中
线程名: Thread-0线程状态:TIMED_WAITING
子线程(Thread-0)运行中
线程名: Thread-0线程状态:TIMED_WAITING
子线程(Thread-0)运行中
线程名: Thread-0线程状态:TERMINATED

线程同步机制

1、在多线程编程,一些敏感的数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性
2、可以这样理解,线程同步:当一个线程在对内存进行操作时,其他线程都不可以对和这个内存地址进行操作,知道该线程完成操作,其他线程才能对该内存地址进行操作
3、实现同步

  • 同步代码块
synchronized(对象){ //得到对象的锁,才能操作同步代码
	//需要被同步的代码
}
  • synchronized还可以放在方法声明中,表示整个方法为同步方法
public synchronized void m (String name){
	//需要被同步的代码
}

例如:

package thread_use;

public class Thread_12 {
    public static void main(String[] args) {
        SellTicket2 sellTicket2 = new SellTicket2();

        Thread thread1 = new Thread(sellTicket2);
        Thread thread2 = new Thread(sellTicket2);
        Thread thread3 = new Thread(sellTicket2);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}

class SellTicket2 implements Runnable{
    private static int ticket_num=5;
    private boolean loop=true;
    // public synchronized void sell()就是一个同步方法
    // 这时锁在this对象
    // 也可以在代码块上写synchronize,就变为同步代码块
    public synchronized void sell(){
        if (ticket_num<=0){
            System.out.println("售票结束...");
            loop=false;
            return;
        }

        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("窗口:"+Thread.currentThread().getName()+" 还剩:"+(--ticket_num)+"张票");
    }

    @Override
    public void run() {
        while(loop) {
            sell(); //sell方法是一种同步方法
        }
    }
}

输出结果:

窗口:Thread-0 还剩:4张票
窗口:Thread-0 还剩:3张票
窗口:Thread-0 还剩:2张票
窗口:Thread-0 还剩:1张票
窗口:Thread-0 还剩:0张票
售票结束...
售票结束...
售票结束...

互斥锁

1、Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性
2、每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象
3、关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任意时刻只能由一个线程访问
4、同步的局限性:导致程序的执行效率降低
5、同步方法(非静态)的锁可以是this,也可以是其他对象(要求同一个对象)
6、同步方法(静态的)的锁为当前类本身

例如:

package thread_use;

public class Thread_13 {
    public static void main(String[] args) {
        SellTicket3 sellTicket3 = new SellTicket3();
        Thread thread1 = new Thread(sellTicket3);
        Thread thread2 = new Thread(sellTicket3);
        Thread thread3 = new Thread(sellTicket3);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}


class SellTicket3 implements Runnable{
    private static int ticket_num=5;
    private boolean loop=true;
    // public synchronized void sell()就是一个同步方法
    // 这时锁在this对象
    // 也可以在代码块上写synchronize,就变为同步代码块,这个互斥锁还是this
    
    // 同步方法(静态的)的锁为当前类本身
    // public synchronzied static void m1() 锁加在 SellTicket3.class
    // 如果在静态方法中,实现一个同步代码块
    /*
	public static void m2(){
		synchronzied(SellTicket3.class){
		   System.out.println("m2");
		}
    }
	*/
    public synchronzied static void m1(){
    }
    public /* synchronized */ void sell(){
        synchronized (this) {
            if (ticket_num <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }

            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口:" + Thread.currentThread().getName() + " 还剩:" + (--ticket_num) + "张票");
        }
    }

    @Override
    public void run() {
        while(loop) {
            sell(); //sell方法是一种同步方法
        }
    }
}

输出结果:

窗口:Thread-0 还剩:4张票
窗口:Thread-0 还剩:3张票
窗口:Thread-0 还剩:2张票
窗口:Thread-0 还剩:1张票
窗口:Thread-0 还剩:0张票
售票结束...
售票结束...
售票结束...

例如:

package thread_use;

import jdk.nashorn.internal.ir.CallNode;

public class Thread_14 {
    public static void main(String[] args) {
        SellTicket4 sellTicket4 = new SellTicket4();

        Thread thread1 = new Thread(sellTicket4);
        Thread thread2 = new Thread(sellTicket4);
        Thread thread3 = new Thread(sellTicket4);

        thread1.start();
        thread2.start();
        thread3.start();
    }
}
class SellTicket4 implements Runnable{
    private static int ticket_num=5;
    private boolean loop=true;
    // public synchronized void sell()就是一个同步方法
    // 这时锁在this对象
    // 也可以在代码块上写synchronize,就变为同步代码块,这个互斥锁还是this
   
    Object object = new Object();
    public /* synchronized */ void sell(){
        synchronized (object) {
            if (ticket_num <= 0) {
                System.out.println("售票结束...");
                loop = false;
                return;
            }

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("窗口:" + Thread.currentThread().getName() + " 还剩:" + (--ticket_num) + "张票");
        }
    }

    @Override
    public void run() {
        while(loop) {
            sell(); //sell方法是一种同步方法
        }
    }
}

输出结果:

窗口:Thread-0 还剩:4张票
窗口:Thread-0 还剩:3张票
窗口:Thread-2 还剩:2张票
窗口:Thread-2 还剩:1张票
窗口:Thread-2 还剩:0张票
售票结束...
售票结束...
售票结束...

注意
1、同步方法如果没有使用static修饰:默认锁对象为this
2、如果方法使用static修饰,默认锁对象:当前类.class
3、实现的落地步骤:

  • 需要先分析锁的代码
  • 选择同步代码块或同步方法
  • 需要多个线程的锁对象为同一个即可

死锁

介绍
多个线程都占用了对方的锁资源,但是不肯相让,导致了死锁,在编程里是一定要避免死锁的发生
例如:

package thread_use;

public class Thread_15 {
    public static void main(String[] args) {
        DeadLock A = new DeadLock(true);
        A.setName("A线程");
        A.start();
        DeadLock B= new DeadLock(false);
        B.setName("B线程");
        B.start();
    }
}

class DeadLock extends Thread{
    static Object o1=new Object();
    static Object o2=new Object();
    boolean flag;
    public DeadLock(boolean flag){
        this.flag=flag;
    }

    @Override
    public void run() {
        //下面的业务逻辑
        //1、如果flag为True,线程A就会先得到或者持有o1对象锁,然后尝试去获取o2对象锁
        //2、如果线程A得不到o2对象锁,就会Blocked
        //3、如果flag为False,线程B就会先得到或者持有o2对象锁,然后尝试去获取o1对象锁
        //4、如果线程B得不到o1对象锁,就会Blocked
        if (flag) {
            synchronized (o1) { //对象互斥锁
                System.out.println(Thread.currentThread().getName() + " 在o1中");
                synchronized (o2) {
                    System.out.println(Thread.currentThread().getName() + " 在o2中");
                }
            }
        }else {
            synchronized (o2) {//对象互斥锁
                System.out.println(Thread.currentThread().getName() + " 在o3中");
                synchronized (o1) {
                    System.out.println(Thread.currentThread().getName() + " 在o4中");
                }
            }
        }
    }
}

输出结果:

A线程 在o1中
B线程 在o3中
#一直不会停~~~

释放锁

1、当前线程的同步方法、同步代码块执行结束
2、当前线程在同步代码块,同步方法中遇到了breakreturn
3、当前线程在同步代码块、同步方法中出现了未处理的ErrorException,导致异常结束
4、当前线程在同步代码块,同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
反例
不会释放锁
1、线程执行同步方法时,程序调用Thread.sleep()Thread.yield()方法暂停当前线程的执行,不会释放锁
2、线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁
提示:应尽量避免使用suspend()resume()来控制线程,方法不在推荐使用

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值