写点什么

Java 线程基础

作者:卢衍飞
  • 2022-11-25
    山东
  • 本文字数:12806 字

    阅读完需:约 42 分钟

线程基础进程线程(数据结构)进程是程序的一次执行过程,或者是政治运行的一个程序。线程是由进程创建,是进程的一个实体,一个进程可以拥有多个线程。


并发并行单线程:同一个时刻,只允许执行一个线程


多线程:同一时刻,可以执行多个线程


并发:同一时刻,多个任务交替执行。单核 CPU 实现的多任务就是并发


并行:同一时刻,多个任务同事执行。多核 CPU 可以实现并行


package opp1;


import org.omg.SendingContext.RunTime;


public class demo01 {public static void main(String[] args) {Runtime runtime = Runtime.getRuntime();int cpuNums = runtime.availableProcessors();System.out.println(cpuNums); //显示 cpu 核数


}
复制代码


}继承 Thread 创建线程创建线程的两种方法:


继承 Thread 类,重写 run 方法实现 runnable 接口,重写 run 方法 package opp1;


/**


  • 继承 Thread 创建线程*/public class demo02 {public static void main(String[] args) {//创建 Cat 对象 Cat cat = new Cat();cat.start(); //启动线程}}


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


class Cat extends Thread{int times = 0;@Overridepublic void run() { //重写 run 方法,写上自己的业务逻辑 while (true) {//每隔一秒。控制台输出“喵喵”,共 10 次.执行完毕结束 System.out.println("喵喵" + (++times));try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}if (times ==10){break; //当 times=10 时候,进程退出}}}}多线程机制当 mian 线程启动一个子线程 Thread-0 ,主线程不会阻塞,会继续执行


package opp1;


/**


  • 继承 Thread 创建线程*/public class demo02 {public static void main(String[] args) throws InterruptedException {//创建 Cat 对象 Cat cat = new Cat();cat.start();//当 mian 线程启动一个子线程 Thread-0 ,主线程不会阻塞,会继续执行//这时,我们的子线程会交替执行

  • }}


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


class Cat extends Thread{int times = 0;@Overridepublic void run() { //重写 run 方法,写上自己的业务逻辑 while (true) {//每隔一秒。控制台输出“喵喵”,共 80 次.执行完毕结束 System.out.println("喵喵" + (++times) + " 子线程"+Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}if (times ==80){break; //当 times=80 时候,进程退出}}}}Java 线程基础插图


start 为什么调用 stat 方法?


cat.start(); //最终会执行 cat 的 run()方法


cat.run(); //run 方法只是一个普通方法,没有真正启动一个线程,就会把 run 方法执行完毕,才向下执行


Java 线程基础插图 1


Runnable 创建线程 package opp1;


/**


  • Runnable 接口 实现创建线程

  • 这里底层使用了设计模式:代理模式*/


public class demo03 {public static void main(String[] args) {Dog dog = new Dog();// dog.start(); 这里不能用 start


    //创建Thread对象,把dog对象(实现Runnable),放入Thread,从而调用start    Thread thread = new Thread(dog);    thread.start();}
复制代码


}


class Dog implements Runnable{ //通过 Runnable 接口,开发线程 int count = 0;@Overridepublic void run() {while(true){System.out.println("小狗汪汪叫 " +(++count) + Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}if (count == 10){break;}}}}子线程 package opp1;


/**


  • main 方法实现两个子线程*/public class demo04 {public static void main(String[] args) {T1 t1 = new T1();T2 t2 = new T2();Thread thread = new Thread(t1); //新建一个进程 Thread thread1 = new Thread(t2);// Thread thread2 = new Thread(t2);thread.start(); //启动第一个子线程 thread1.start(); //启动第二个子线程}}


class T1 implements Runnable{


int count = 0;@Overridepublic void run() {
while (true) { System.out.println("hello world" + (++count));
try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); }
if (count == 5) { break; } }}
复制代码


}


class T2 implements Runnable{


int count = 0;@Overridepublic void run() {
while (true) { System.out.println(" hi" + (++count));
try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); }
if (count == 5) { break; } }}
复制代码


}多线程售票经典售票问题


package opp1;


/**


  • 使用多线程,模拟三个窗口同时售票,每个窗口都会卖出 100 张票*/


public class demo05 {public static void main(String[] args) {


    /**     * 使用继承 Thread     * 会出现超卖的现象,sleep时间越短,就会出现超卖现象     */
复制代码


// SellTicket01 sellTicket01 = new SellTicket01();// SellTicket01 sellTicket02 = new SellTicket01();// SellTicket01 sellTicket03 = new SellTicket01();// ////// //会出现超卖的现象,sleep 时间越短,就会出现超卖现象// sellTicket01.start();// sellTicket02.start();// sellTicket03.start();


    /**     * 使用Runnable方法     * 会出现超卖的现象,sleep时间越短,就会出现超卖现象     */    SellTicket02 sellTicket021 = new SellTicket02();
Thread thread = new Thread(sellTicket021); Thread thread1 = new Thread(sellTicket021); Thread thread2 = new Thread(sellTicket021);
thread.start(); thread1.start(); thread2.start();
}
复制代码


}


class SellTicket01 extends Thread{


private static int num = 100;   //让多个线程共享num
//快捷键 CTRL + O ,选run方法@Overridepublic void run() { while (true){ if (num <=0){ System.out.println(Thread.currentThread().getName() + "售票结束"); break; }
try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
复制代码


}


class SellTicket02 implements Runnable{private static int num = 100; //让多个线程共享 num@Overridepublic void run() {while (true){if (num <=0){System.out.println(Thread.currentThread().getName() + "售票结束");break;}


        try {            Thread.sleep(5);        } catch (InterruptedException e) {            throw new RuntimeException(e);        }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
复制代码


}通知线程退出当线程完成任务后,会自动退出还可以通过 使用变量 来控制 run 方法退出的方式停止线程,即 通知方式 package opp1;


public class demo06 {public static void main(String[] args) throws InterruptedException {T t1 = new T();t1.start();


    //如果希望主线程main 去控制t1,必须可以修改loop    //让t1 退出run方法,从而终止 t1线程 -> 通知方式
//让主线程休眠10秒,再通知t1线程退出 System.out.println("main线程休眠10s"); Thread.sleep(10 * 1000); t1.setLoop(false);
}
复制代码


}


class T extends Thread{int count = 0;private boolean loop = true;@Overridepublic void run() {while (loop){


        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            throw new RuntimeException(e);        }        System.out.println("执行" + (++count));    }}
public void setLoop(boolean loop) { this.loop = loop;}
复制代码


}线程中断线程常用的方法第一组:


setName //设置线程名称 getName //返回该线程名称 start //使该线程开始执行;Java 虚拟机底层调用该线程的 start0 方法 run //调用线程对象 run 方法 setPriority //修改线程优先级 getPriority //获得线程优先级 sleep //在指定的毫秒数没让当前正在执行的线程休眠 interrupt //中断进程注意事项和细节


start 底层会创建新的进程,调用 run,run 就是一个简单方法调用,不会启动新线程线程优先级的范围 interrupt,中断进程,但是并没有真正结束进程。多以一般用于种端正在休眠的进程 sleep:线程的静态方法,使当前线程休眠 package opp1;


public class demo07 {public static void main(String[] args) throws InterruptedException {T3 t3 = new T3();t3.setName("摩拉克斯");t3.setPriority(Thread.MIN_PRIORITY);t3.start();


    System.out.println(t3.getName());    System.out.println("优先级"+ t3.getPriority());
//主线程先打印5个hi ,然后中断子线程的休眠 for (int i = 0; i < 5; i++) { Thread.sleep(1000); System.out.println("hi" +i); } t3.interrupt(); //当执行到这里时,就会中断 t3的线程
}
复制代码


}


class T3 extends Thread{ //自定义的线程类 @Overridepublic void run() {for (int i = 0; i < 100; i++) {//Thread.currentThread().getName() 获取当前线程的名称 System.out.println(Thread.currentThread().getName() + "吃包子" + i);}


    try {        System.out.println(Thread.currentThread().getName()+ "休眠中...");        Thread.sleep(20000);    } catch (InterruptedException e) {        //当该线程执行到一个interrupt时,就会catch 一个异常,可以加入自己的业务代码        //InterruptedException 是捕获到了一个中断异常,而不是终止        System.out.println(Thread.currentThread().getName() + "被 interrupt了");    }}
复制代码


}线程插队常用方法第二组


yield : 线程的礼让。让出 CPU,让其他线程执行,但是礼让时间不确定,所以也不一定礼让成功 join :线程插队。插队的线程一旦插队成功,则肯定先执行完插入线程的所有任务。package opp1;


public class demo08 {public static void main(String[] args) throws InterruptedException {T5 t5 = new T5();t5.start();


    for (int i = 1; i <= 20; i++) {        Thread.sleep(1000);        System.out.println("吃了" + i + "包子");        if (i == 5) {            System.out.println("================先吃了" + i + "包子===============");            //join 线程插队,一定成功            t5.join();   //再吃饺子
复制代码


// Thread.yield(); //线程礼让,不一定成功,看 cpu 心情 System.out.println("=============饺子吃完了,又开始吃包子=============");}}}}


class T5 extends Thread{@Overridepublic void run() {for (int i = 1; i <= 20 ; i++) {try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("吃了" + i + "饺子 JoinThread----------");}}}线程插队练习 package opp1;


/**


  • 主线程每隔 1s,输出 hi,一共 10 次

  • 当输出 hi 5 时,启动一个子线程(要求 runnable),每隔 1s 输出 hello ,等该线程输出 10 次 hello 后,退出

  • 主线程继续输出

  • 程序结束*/public class demo09 {public static void main(String[] args) throws InterruptedException {T6 t6 = new T6();Thread thread = new Thread(t6);for (int i = 1; i <= 10 ; i++) {System.out.println("hi " + i);if (i == 5){//说明输出了 5 次 hithread.start();thread.join(); //立即将 t6 子线程插入到主线程}Thread.sleep(1000); //输出一次 hi,让 main 线程也休眠 1s}}}


class T6 implements Runnable{int count = 0;@Overridepublic void run() {while (true){System.out.println("hello " + (++count));


        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            throw new RuntimeException(e);        }
if (count == 10){ break; } }}
复制代码


}守护线程用户现场和守护线程


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


public class demo10 {public static void main(String[] args) throws InterruptedException {T7 t7 = new T7();


    //如果我们希望当main主线程结束后,子线程自动结束    //只需要将子线程 设为守护线程    t7.setDaemon(true);    //将子线程设为守护线程    t7.start();
for (int i = 0; i < 10; i++) { System.out.println("nahida 快来" + i); Thread.sleep(1000); }}
复制代码


}


class T7 extends Thread{@Overridepublic void run() {for ( ; ;){ //无限循环 try {Thread.sleep(500); //休眠 50ms} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("须弥什么时候开啊,等不及了");}}}线程 7 大状态 JDK:在 Thread.State 中(操作系统中的几种状态:挂起、就绪、运行、阻塞、终止等几个状态)


Java 线程基础插图 2


Java 线程基础插图 3


runnable 状态是处于可运行状态。


Java 线程基础插图 4


package opp1;


public class demo11 {public static void main(String[] args) throws InterruptedException {T8 t8 = new T8();System.out.println("状态 " + t8.getState());


    t8.start();    while (Thread.State.TERMINATED != t8.getState()){        System.out.println("状态 " + t8.getState());        Thread.sleep(500);    }    System.out.println("状态 " + t8.getState());}
复制代码


}


class T8 extends Thread{@Overridepublic void run() {while (true){for (int i = 0; i < 10; i++) {System.out.println("hi" + i);try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}break;}}}线程同步机制在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性也可以这里理解:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,知道该线程完成操作,其他线程才能对该内存地址进行操作 package opp1;


/**


  • 使用多线程,模拟三个窗口同时售票,每个窗口都会卖出 100 张票*/


public class demo05 {public static void main(String[] args) {


    /**     * 使用继承 Thread     * 会出现超卖的现象,sleep时间越短,就会出现超卖现象     */
复制代码


// SellTicket01 sellTicket01 = new SellTicket01();// SellTicket01 sellTicket02 = new SellTicket01();// SellTicket01 sellTicket03 = new SellTicket01();// ////// //会出现超卖的现象,sleep 时间越短,就会出现超卖现象// sellTicket01.start();// sellTicket02.start();// sellTicket03.start();


    /**     * 使用Runnable方法     * 会出现超卖的现象,sleep时间越短,就会出现超卖现象     */
复制代码


// SellTicket02 sellTicket021 = new SellTicket02();//// Thread thread = new Thread(sellTicket021);// Thread thread1 = new Thread(sellTicket021);// Thread thread2 = new Thread(sellTicket021);//// thread.start();// thread1.start();// thread2.start();


    /**     * 实现接口方法,使用synchronize实现线程同步     */    SellTicket03 sellTicket031 = new SellTicket03();    Thread thread = new Thread(sellTicket031);    Thread thread1 = new Thread(sellTicket031);    Thread thread2 = new Thread(sellTicket031);    //
//不会出现超卖的现象 thread.start(); thread1.start(); thread2.start();
}
复制代码


}


//实现接口方法,使用 synchronize 实现线程同步//因为这里涉及到多个线程共享资源,所以我们使用实现 Runnable 方式(重要)


class SellTicket03 implements Runnable{


private static int num = 100;   //让多个线程共享numprivate boolean loop = true;
public synchronized void sell(){ //同步方法,在同一时刻,只能有一个线程来执行sell方法 if (num <=0){ System.out.println(Thread.currentThread().getName() + "售票结束"); loop = false; return; }
try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num));}
//快捷键 CTRL + O ,选run方法@Overridepublic void run() { while (loop){ sell(); //sell 是一个同步方法 }}
复制代码


}


//============================================================================================


class SellTicket01 extends Thread{


private static int num = 100;   //让多个线程共享num
//快捷键 CTRL + O ,选run方法@Overridepublic void run() { while (true){ if (num <=0){ System.out.println(Thread.currentThread().getName() + "售票结束"); break; }
try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
复制代码


}


class SellTicket02 implements Runnable{private static int num = 100; //让多个线程共享 num@Overridepublic void run() {while (true){if (num <=0){System.out.println(Thread.currentThread().getName() + "售票结束");break;}


        try {            Thread.sleep(5);        } catch (InterruptedException e) {            throw new RuntimeException(e);        }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
复制代码


}互斥锁引入对象互斥锁的概念,来保证共享数据的完整性每个对象都对应一个可称为“互斥锁”的标记,这个标记用来保证任一时刻,只能由一个线程访问该对象关键字 synchronized 来与对象互斥锁练习,当某个对象用 synchronized 修饰时,表面该对象在任一时刻只能由一个线程访问同步的局限性:倒置程序的执行效率要降低同步方法(非静态的)的锁可以是 this ,也可以是其他对象(要求是同一个对象)同步方法(静态的)的锁为当前类本身 package opp1;


/**


  • 使用多线程,模拟三个窗口同时售票,每个窗口都会卖出 100 张票*/


public class demo05 {public static void main(String[] args) {


    /**     * 使用继承 Thread     * 会出现超卖的现象,sleep时间越短,就会出现超卖现象     */
复制代码


// SellTicket01 sellTicket01 = new SellTicket01();// SellTicket01 sellTicket02 = new SellTicket01();// SellTicket01 sellTicket03 = new SellTicket01();// ////// //会出现超卖的现象,sleep 时间越短,就会出现超卖现象// sellTicket01.start();// sellTicket02.start();// sellTicket03.start();


    /**     * 使用Runnable方法     * 会出现超卖的现象,sleep时间越短,就会出现超卖现象     */
复制代码


// SellTicket02 sellTicket021 = new SellTicket02();//// Thread thread = new Thread(sellTicket021);// Thread thread1 = new Thread(sellTicket021);// Thread thread2 = new Thread(sellTicket021);//// thread.start();// thread1.start();// thread2.start();


    /**     * 实现接口方法,使用synchronize实现线程同步     */    SellTicket03 sellTicket031 = new SellTicket03();    Thread thread = new Thread(sellTicket031);    Thread thread1 = new Thread(sellTicket031);    Thread thread2 = new Thread(sellTicket031);    //
//不会出现超卖的现象 thread.start(); thread1.start(); thread2.start();
}
复制代码


}


//实现接口方法,使用 synchronize 实现线程同步//1. public synchronized void sell() 就是一个同步方法 【非静态】//2. 这时锁在 this 对象 【非静态】//3. 也可以在代码块上写 synchronized , 如:class SellTicket04,互斥锁还是在 this 对象 【非静态】


class SellTicket03 implements Runnable{//因为这里涉及到多个线程共享资源,所以我们使用实现 Runnable 方式(重要)


private static int num = 100;   //多个线程共享numprivate boolean loop = true;
复制代码


// ///////【同步方法(静态)】的锁为当前类本身!!!// ///////public synchronized static void m1() 的锁加在 SellTicket03.class!!!【静态同步方法】// ///////这里的 m1()方法使用时 static 修饰,所以是静态同步方法 【静态同步方法】//// public synchronized static void m1(){//// }//// ///////这里的 m2()方法使用 static 修饰,则底下的 synchronized 代码块也是【静态同步方法】


//


// public static void m2(){// synchronized (SellTicket03.class) {


// ///////如果在【静态同步方法】中,实现一个同步代码块,synchronized (当前类名.class) !!!// System.out.println("m2");// }// }


public synchronized void sell(){   //同步方法,在同一时刻,只能有一个线程来执行sell方法  【非静态】    if (num <=0){        System.out.println(Thread.currentThread().getName() + "售票结束");        loop = false;        return;    }
try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num));}
//快捷键 CTRL + O ,选run方法@Overridepublic void run() { while (loop){ sell(); //sell 是一个同步方法 }}
复制代码


}


//3. 也可以在代码块上写 synchronized , 如:class SellTicket04,互斥锁还在 this 对象 【非静态】


class SellTicket04 implements Runnable{//因为这里涉及到多个线程共享资源,所以我们使用实现 Runnable 方式(重要)


private static int num = 100;   //让多个线程共享numprivate boolean loop = true;Object object = new Object();
public void sell() { //同步方法,在同一时刻,只能有一个线程来执行sell方法 【非静态】 synchronized (this) { //同步代码块!!!!! 【非静态】
复制代码


// synchronized (object) { //同步代码块!!!互斥锁还在 this 对象 object 【非静态】if (num <= 0) {System.out.println(Thread.currentThread().getName() + "售票结束");loop = false;return;}


        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            throw new RuntimeException(e);        }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
//快捷键 CTRL + O ,选run方法@Overridepublic void run() { while (loop){ sell(); //sell 是一个同步方法 }}
复制代码


}


//===================================================================================================


class SellTicket01 extends Thread{


private static int num = 100;   //让多个线程共享num
//快捷键 CTRL + O ,选run方法@Overridepublic void run() { while (true){ if (num <=0){ System.out.println(Thread.currentThread().getName() + "售票结束"); break; }
try { Thread.sleep(500); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
复制代码


}


class SellTicket02 implements Runnable{private static int num = 100; //让多个线程共享 num@Overridepublic void run() {while (true){if (num <=0){System.out.println(Thread.currentThread().getName() + "售票结束");break;}


        try {            Thread.sleep(5);        } catch (InterruptedException e) {            throw new RuntimeException(e);        }
System.out.println("窗口线程名称:" + Thread.currentThread().getName() + " 还剩票数:" + (--num)); }}
复制代码


}注意事项


同步方法如果没有使用 static 修饰,默认锁对象为 this 如果同步方法使用 static 修饰,默认锁对象:当前类.class 实现的落地步骤需要分析上锁的代码选择同步代码块或同步方法(尽量使用同步代码块)要求多个线程的锁对象为同一个即可进程死锁多个线程都占用了对方的锁资源,但不肯相让,导致了死索,在编程时一定要避免死锁的发生


package opp1;


import javax.swing.plaf.synth.SynthOptionPaneUI;


public class demo12 {public static void main(String[] args) {//模拟一个死锁现象 DeadLockDemo A = new DeadLockDemo(true);DeadLockDemo B = new DeadLockDemo(false);A.setName("A 线程");B.setName("B 线程");A.start();B.start();


}
复制代码


}


class DeadLockDemo extends Thread{static Object o1 = new Object();static Object o2 = new Object();boolean flag;


public DeadLockDemo(boolean flag){     //构造器    this.flag = flag;}
@Overridepublic void run(){
//下面业务逻辑的分析 //1. 如果flag 为T ,线程就会先得到/持有 o1 对象锁 //2. 如果线程A 得不到o2 对象锁,就会Blocked; //3. 如果flag 为False ,线程B 就会先得到/持有 o2对象锁,然后尝试获取o1对象锁 //4. 如果线程B 得到o1 对象锁,就会Blocked
if (flag){ synchronized (o1){ //对象互斥锁,下面就是同步代码 System.out.println(Thread.currentThread().getName() +" 进入1"); synchronized (o2){ //这里获得li对象的监视权 System.out.println(Thread.currentThread().getName() +" 进入2"); } } }else { synchronized (o2){ System.out.println(Thread.currentThread().getName() +" 进入3"); synchronized (o1){ //这里获得li对象的监视权 System.out.println(Thread.currentThread().getName() +" 进入4"); } } }}
复制代码


}释放锁下面的操作会释放锁


当前线程的同步方法、同步代码块执行结束当前线程在同步代码块、同步方法遇到 break、return 当前线程在同步代码块、同步方法中出现未处理的 Error 或者 Exception,导致异常结束当前线程在同步代码块、同步方法中执行了线程对象的 wait( ) 方法,当前线程暂停,并释放锁。下面的操作不会释放锁


线程执行同步代码块或同步方法时,线程调用 sleep、yield 方法暂停当前线程的执行,不会释放锁


线程执行同步代码块时,其他线程调用了该线程的 suspend( ) 方法将该线程挂起,该线程不会释放锁。


提示:应尽量避免使用 suspend 和 resume 来控制线程,这两种方法不再推荐使用。


作业作业一 Java 线程基础插图 5


方法一:


main 先启动 TA、TB 两个线程


TA 先继续打印随机数,TB 等待键盘输入“Q”指令


键盘输入“Q”指令,TB 通知 TA 停止。通过中间变量 loop 实现通知。


package opp1;


import java.util.Random;import java.util.Scanner;


public class demo13 {public static void main(String[] args) {TA ta = new TA();Thread thread1 = new Thread(ta);thread1.start();TB tb = new TB(ta); //一定要注意 tb.start();


}
复制代码


}


class TA implements Runnable{private boolean loop = true;


@Overridepublic void run() {
while (loop){ System.out.println((int)(Math.random()*100+1)); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); }
}
}
public void setLoop(boolean loop) { //可以修改loop this.loop = loop;}
复制代码


}


class TB extends Thread{private TA ta;private Scanner scanner = new Scanner(System.in);


public TB(TA ta) {  //构造器中,直接传入TA对象    this.ta = ta;}
String str = " ";@Overridepublic void run() { while (true) { System.out.println("输入Q 停止"); char key = scanner.next().toUpperCase().charAt(0); if (key == 'Q') { ta.setLoop(false); System.out.println("B退出"); break; }
}}
复制代码


}方法二:进程守护


作业二 Java 线程基础插图 6


package opp1;


public class demo16 {public static void main(String[] args) {Bank bank = new Bank();Thread t1 = new Thread(bank);Thread t2 = new Thread(bank);t1.setName("摩拉克斯");t2.setName("巴巴托斯");


    t1.start();    t2.start();}
复制代码


}


/**


  • 因为这里涉及到多个线程共享资源,所以我们使用实现 Runnable 方式*/


class Bank implements Runnable{private int money = 10000;@Overridepublic void run() {/*** 1. 这里使用 synchronized 实现线程同步* 2. 当多个线程执行到这里时,就会去争夺 this 对象锁* 3. 哪个线程争夺到 this 对象锁,就执行 synchronized 代码块,执行完后会释放 this 对象锁* 4. 争夺不到 this 对象锁,就 blocked,准备继续争夺* 5. this 对象锁是非公平锁*/while (true){synchronized(this) {if (money < 1000) {System.out.println("余额不足");break;}


            money -=1000;            System.out.println(Thread.currentThread().getName() + "取出了1000元   当前余额为" + money + "元");        }
try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } }}
复制代码


}

发布于: 刚刚阅读数: 4
用户头像

卢衍飞

关注

君子藏器于腹,待时而动. 2022-11-08 加入

宜塔阿里巴巴低代码高级开发师 腾讯云V加开发者认证 HarmonyOS应用开发者认证 华为云云享专家Java开发工程师

评论

发布
暂无评论
Java 线程基础_Java_卢衍飞_InfoQ写作社区