程的优先级与线程让位、合并、守护线程

92 阅读5分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

哈喽,大家好!我是Why,一名在读学生,目前刚刚开始进入自己的编程学习生涯。虽然学习起步较晚,但我坚信做了才有0或1的可能。学了一段时间以后也是选择在掘金上分享自己的日常笔记,也希望能够在众多道友的大家庭中打成一片。 本文主要讲解程的优先级与线程让位、合并、守护线程,如果大家读后觉得有用的话,还请大家多多支持博主:欢迎 ❤️点赞👍、收藏⭐、留言💬 ✨✨✨个人主页:JinHuan

程的优先级

 /*
 怎么合理的终止一个线程的执行。这种方式是很常用的。
  */
 public class ThreadTest10 {
     public static void main(String[] args) {
         MyRunable4 r = new MyRunable4();
         Thread t = new Thread(r);
         t.setName("t");
         t.start();
 ​
         // 模拟5秒
         try {
             Thread.sleep(5000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         // 终止线程
         // 你想要什么时候终止t的执行,那么你把标记修改为false,就结束了。
         r.run = false;
     }
 }
 ​
 class MyRunable4 implements Runnable {
 ​
     // 打一个布尔标记
     boolean run = true;
 ​
     @Override
     public void run() {
         for (int i = 0; i < 10; i++){
             if(run){
                 System.out.println(Thread.currentThread().getName() + "--->" + i);
                 try {
                     Thread.sleep(1000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
             }else{
                 // return就结束了,你在结束之前还有什么没保存的。
                 // 在这里可以保存呀。
                 //save....
 ​
                 //终止当前线程
                 return;
             }
         }
     }
 }

线程让位

 /*
 让位,当前线程暂停,回到就绪状态,让给其它线程。
 静态方法:Thread.yield();
  */
 public class ThreadTest12 {
     public static void main(String[] args) {
         Thread t = new Thread(new MyRunnable6());
         t.setName("t");
         t.start();
 ​
         for(int i = 1; i <= 10000; i++) {
             System.out.println(Thread.currentThread().getName() + "--->" + i);
         }
     }
 }
 ​
 class MyRunnable6 implements Runnable {
 ​
     @Override
     public void run() {
         for(int i = 1; i <= 10000; i++) {
             //每100个让位一次。
             if(i % 100 == 0){
                 Thread.yield(); // 当前线程暂停一下,让给主线程。
             }
             System.out.println(Thread.currentThread().getName() + "--->" + i);
         }
     }
 }
 ​

线程合并

 /*
 线程合并
  */
 public class ThreadTest13 {
     public static void main(String[] args) {
         System.out.println("main begin");
 ​
         Thread t = new Thread(new MyRunnable7());
         t.setName("t");
         t.start();
 ​
         //合并线程
         try {
             t.join(); // t合并到当前线程中,当前线程受阻塞,t线程执行直到结束。
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
 ​
         System.out.println("main over");
     }
 }
 ​
 class MyRunnable7 implements Runnable {
 ​
     @Override
     public void run() {
         for(int i = 0; i < 10000; i++){
             System.out.println(Thread.currentThread().getName() + "--->" + i);
         }
     }
 }
 ​

守护线程

 /*
 守护线程
  */
 public class ThreadTest14 {
     public static void main(String[] args) {
         Thread t = new BakDataThread();
         t.setName("备份数据的线程");
 ​
         // 启动线程之前,将线程设置为守护线程
         t.setDaemon(true);
 ​
         t.start();
 ​
         // 主线程:主线程是用户线程
         for(int i = 0; i < 10; i++){
             System.out.println(Thread.currentThread().getName() + "--->" + i);
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }
 ​
 class BakDataThread extends Thread {
     public void run(){
         int i = 0;
         // 即使是死循环,但由于该线程是守护者,当用户线程结束,守护线程自动终止。
         while(true){
             System.out.println(Thread.currentThread().getName() + "--->" + (++i));
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     }
 }

生产者和消费者模式

 import java.util.ArrayList;
 import java.util.List;
 ​
 /*
 1、使用wait方法和notify方法实现“生产者和消费者模式”
 ​
 2、什么是“生产者和消费者模式”?
     生产线程负责生产,消费线程负责消费。
     生产线程和消费线程要达到均衡。
     这是一种特殊的业务需求,在这种特殊的情况下需要使用wait方法和notify方法。
 ​
 3、wait和notify方法不是线程对象的方法,是普通java对象都有的方法。
 ​
 4、wait方法和notify方法建立在线程同步的基础之上。因为多线程要同时操作一个仓库。有线程安全问题。
 ​
 5、wait方法作用:o.wait()让正在o对象上活动的线程t进入等待状态,并且释放掉t线程之前占有的o对象的锁。
 ​
 6、notify方法作用:o.notify()让正在o对象上等待的线程唤醒,只是通知,不会释放o对象上之前占有的锁。
 ​
 7、模拟这样一个需求:
     仓库我们采用List集合。
     List集合中假设只能存储1个元素。
     1个元素就表示仓库满了。
     如果List集合中元素个数是0,就表示仓库空了。
     保证List集合中永远都是最多存储1个元素。
 ​
     必须做到这种效果:生产1个消费1个。
  */
 public class ThreadTest16 {
     public static void main(String[] args) {
         // 创建1个仓库对象,共享的。
         List list = new ArrayList();
         // 创建两个线程对象
         // 生产者线程
         Thread t1 = new Thread(new Producer(list));
         // 消费者线程
         Thread t2 = new Thread(new Consumer(list));
 ​
         t1.setName("生产者线程");
         t2.setName("消费者线程");
 ​
         t1.start();
         t2.start();
     }
 }
 ​
 // 生产线程
 class Producer implements Runnable {
     // 仓库
     private List list;
 ​
     public Producer(List list) {
         this.list = list;
     }
     @Override
     public void run() {
         // 一直生产(使用死循环来模拟一直生产)
         while(true){
             // 给仓库对象list加锁。
             synchronized (list){
                 if(list.size() > 0){ // 大于0,说明仓库中已经有1个元素了。
                     try {
                         // 当前线程进入等待状态,并且释放Producer之前占有的list集合的锁。
                         list.wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
                 // 程序能够执行到这里说明仓库是空的,可以生产
                 Object obj = new Object();
                 list.add(obj);
                 System.out.println(Thread.currentThread().getName() + "--->" + obj);
                 // 唤醒消费者进行消费
                 list.notifyAll();
             }
         }
     }
 }
 ​
 // 消费线程
 class Consumer implements Runnable {
     // 仓库
     private List list;
 ​
     public Consumer(List list) {
         this.list = list;
     }
 ​
     @Override
     public void run() {
         // 一直消费
         while(true){
             synchronized (list) {
                 if(list.size() == 0){
                     try {
                         // 仓库已经空了。
                         // 消费者线程等待,释放掉list集合的锁
                         list.wait();
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
                 // 程序能够执行到此处说明仓库中有数据,进行消费。
                 Object obj = list.remove(0);
                 System.out.println(Thread.currentThread().getName() + "--->" + obj);
                 // 唤醒生产者生产。
                 list.notifyAll();
             }
         }
     }
 }

定时器

 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Timer;
 import java.util.TimerTask;
 ​
 /*
 使用定时器指定定时任务。
  */
 public class TimerTest {
     public static void main(String[] args) throws Exception {
 ​
         // 创建定时器对象
         Timer timer = new Timer();
         //Timer timer = new Timer(true); //守护线程的方式
 ​
         // 指定定时任务
         //timer.schedule(定时任务, 第一次执行时间, 间隔多久执行一次);
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         Date firstTime = sdf.parse("2020-03-14 09:34:30");
         //timer.schedule(new LogTimerTask() , firstTime, 1000 * 10);
         // 每年执行一次。
         //timer.schedule(new LogTimerTask() , firstTime, 1000 * 60 * 60 * 24 * 365);
 ​
         //匿名内部类方式
         timer.schedule(new TimerTask(){
             @Override
             public void run() {
                 // code....
             }
         } , firstTime, 1000 * 10);
 ​
     }
 }
 ​
 // 编写一个定时任务类
 // 假设这是一个记录日志的定时任务
 class LogTimerTask extends TimerTask {
 ​
     @Override
     public void run() {
         // 编写你需要执行的任务就行了。
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         String strTime = sdf.format(new Date());
         System.out.println(strTime + ":成功完成了一次数据备份!");
     }
 }
 ​