zoukankan      html  css  js  c++  java
  • Java多线程:超详细的线程方法合集

     1、线程的基础方法

    package com.lyq.java.thread;
    /*
    1、怎么获取当前线程对象?
        Thread t = Thread.currentThread();
        返回值t就是当前线程。
    
    2、获取线程对象的名字
        String name = 线程对象.getName();
    
    3、修改线程对象的名字
        线程对象.setName("线程名字");
    
    4、当线程没有设置名字的时候,默认的名字有什么规律?(了解一下)
        Thread-0
        Thread-1
        Thread-2
        Thread-3
        .....
     */
    public class ThreadTest05 {
        public void doSome(){
            // 这样就不行了
            //this.getName();
            //super.getName();
            // 但是这样可以
            String name = Thread.currentThread().getName();
            System.out.println("------->" + name);
        }
    
        public static void main(String[] args) {
            ThreadTest05 tt = new ThreadTest05();
            tt.doSome();
    
            //currentThread就是当前线程对象
            // 这个代码出现在main方法当中,所以当前线程就是主线程。
            Thread currentThread = Thread.currentThread();
            System.out.println(currentThread.getName()); //main
    
            // 创建线程对象
            MyThread2 t = new MyThread2();
            // 设置线程的名字
            t.setName("t1");
            // 获取线程的名字
            String tName = t.getName();
            System.out.println(tName); //Thread-0
    
            MyThread2 t2 = new MyThread2();
            t2.setName("t2");
            System.out.println(t2.getName()); //Thread-1
            t2.start();
    
            // 启动线程
            t.start();
        }
    }
    
    class MyThread2 extends Thread {
        public void run(){
            for(int i = 0; i < 100; i++){
                // currentThread就是当前线程对象。当前线程是谁呢?
                // 当t1线程执行run方法,那么这个当前线程就是t1
                // 当t2线程执行run方法,那么这个当前线程就是t2
                Thread currentThread = Thread.currentThread();
                System.out.println(currentThread.getName() + "-->" + i);
    
                //System.out.println(super.getName() + "-->" + i);
                //System.out.println(this.getName() + "-->" + i);
            }
        }
    }
    

    2、Thread.sleep()

    package com.lyq.java.thread;
    /*
    关于线程的sleep方法:
        static void sleep(long millis)
        1、静态方法:Thread.sleep(1000);
        2、参数是毫秒
        3、作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其它线程使用。
            这行代码出现在A线程中,A线程就会进入休眠。
            这行代码出现在B线程中,B线程就会进入休眠。
        4、Thread.sleep()方法,可以做到这种效果:
            间隔特定的时间,去执行一段特定的代码,每隔多久执行一次。
     */
    public class ThreadTest06 {
        public static void main(String[] args) {
    
            // 让当前线程进入休眠,睡眠5秒
            // 当前线程是主线程!!!
            /*try {
                Thread.sleep(1000 * 5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/
    
            // 5秒之后执行这里的代码
            //System.out.println("hello world!");
    
            for(int i = 0; i < 10; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
    
                // 睡眠1秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    3、关于Thread.sleep()方法的一个面试题

    package com.lyq.java.thread;
    /*
    关于Thread.sleep()方法的一个面试题:
     */
    public class ThreadTest07 {
        public static void main(String[] args) {
            // 创建线程对象
            Thread t = new MyThread3();
            t.setName("t");
            t.start();
    
            // 调用sleep方法
            try {
                // 问题:这行代码会让线程t进入休眠状态吗?
                t.sleep(1000 * 5); // 在执行的时候还是会转换成:Thread.sleep(1000 * 5);
                                         // 这行代码的作用是:让当前线程进入休眠,也就是说main线程进入休眠。
                                         // 这样代码出现在main方法中,main线程睡眠。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // 5秒之后这里才会执行。
            System.out.println("hello World!");
        }
    }
    
    class MyThread3 extends Thread {
        public void run(){
            for(int i = 0; i < 10000; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
            }
        }
    }
    

    4、终止线程的睡眠:interrupt()

    package com.lyq.java.thread;
    /*
    sleep睡眠太久了,如果希望半道上醒来,你应该怎么办?也就是说怎么叫醒一个正在睡眠的线程??
        注意:这个不是终断线程的执行,是终止线程的睡眠。
     */
    public class ThreadTest08 {
        public static void main(String[] args) {
            Thread t = new Thread(new MyRunnable2());
            t.setName("t");
            t.start();
    
            // 希望5秒之后,t线程醒来(5秒之后主线程手里的活儿干完了。)
            try {
                Thread.sleep(1000 * 5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 终断t线程的睡眠(这种终断睡眠的方式依靠了java的异常处理机制。)
            t.interrupt(); // 干扰,一盆冷水过去!
        }
    }
    
    class MyRunnable2 implements Runnable {
    
        // 重点:run()当中的异常不能throws,只能try catch
        // 因为run()方法在父类中没有抛出任何异常,子类不能比父类抛出更多的异常。
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "---> begin");
            try {
                // 睡眠1年
                Thread.sleep(1000 * 60 * 60 * 24 * 365);
            } catch (InterruptedException e) {
                // 打印异常信息
                //e.printStackTrace();
            }
            //1年之后才会执行这里
            System.out.println(Thread.currentThread().getName() + "---> end");
    
            // 调用doOther
            //doOther();
        }
    
        // 其它方法可以throws
        /*public void doOther() throws Exception{
    
        }*/
    }
    

    5、强行终止一个线程的执行:stop()

    package com.lyq.java.thread;
    /*
    在java中怎么强行终止一个线程的执行。
        这种方式存在很大的缺点:容易丢失数据。因为这种方式是直接将线程杀死了,
        线程没有保存的数据将会丢失。不建议使用。
     */
    public class ThreadTest09 {
        public static void main(String[] args) {
            Thread t = new Thread(new MyRunnable3());
            t.setName("t");
            t.start();
    
            // 模拟5秒
            try {
                Thread.sleep(1000 * 5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 5秒之后强行终止t线程
            t.stop(); // 已过时(不建议使用。)
        }
    }
    
    class MyRunnable3 implements Runnable {
    
        @Override
        public void run() {
            for(int i = 0; i < 10; i++){
                System.out.println(Thread.currentThread().getName() + "--->" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    6、合理的终止一个线程的执行

    package com.lyq.java.thread;
    /*
    怎么合理的终止一个线程的执行。这种方式是很常用的。
     */
    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;
                }
            }
        }
    }
    

    7、了解:关于线程的优先级

    package com.lyq.java.thread;
    
    /*
    了解:关于线程的优先级
     */
    public class ThreadTest11 {
        public static void main(String[] args) {
            // 设置主线程的优先级为1
            Thread.currentThread().setPriority(1);
    
            /*System.out.println("最高优先级" + Thread.MAX_PRIORITY);
            System.out.println("最低优先级" + Thread.MIN_PRIORITY);
            System.out.println("默认优先级" + Thread.NORM_PRIORITY);*/
    
            // 获取当前线程对象,获取当前线程的优先级
            Thread currentThread = Thread.currentThread();
            // main线程的默认优先级是:5
            //System.out.println(currentThread.getName() + "线程的默认优先级是:" + currentThread.getPriority());
    
            Thread t = new Thread(new MyRunnable5());
            t.setPriority(10);
            t.setName("t");
            t.start();
    
            // 优先级较高的,只是抢到的CPU时间片相对多一些。
            // 大概率方向更偏向于优先级比较高的。
            for(int i = 0; i < 10000; i++){
                System.out.println(Thread.currentThread().getName() + "-->" + i);
            }
    
    
        }
    }
    
    class MyRunnable5 implements Runnable {
    
        @Override
        public void run() {
            // 获取线程优先级
            //System.out.println(Thread.currentThread().getName() + "线程的默认优先级:" + Thread.currentThread().getPriority());
            for(int i = 0; i < 10000; i++){
                System.out.println(Thread.currentThread().getName() + "-->" + i);
            }
        }
    }
    
    

    8、线程让位:Thread.yield()

    package com.lyq.java.thread;
    
    /*
    让位,当前线程暂停,回到就绪状态,让给其它线程。
    静态方法: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);
            }
        }
    }
    

    9、线程合并

    package com.lyq.java.thread;
    
    /*
    线程合并
     */
    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);
            }
        }
    }
    

    10、守护线程

    package com.lyq.java.thread;
    /*
    守护线程
     */
    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();
                }
            }
        }
    }
    

    11、生产者和消费者模式

    package com.lyq.java.thread;
    
    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();
                }
            }
        }
    }

    12、定时器:Timer

    package com.lyq.java.thread;
    
    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 + ":成功完成了一次数据备份!");
        }
    }
    

      

  • 相关阅读:
    MyEclipse编码集设置
    Tomcat内存溢出问题解决
    避免头文件多次编译
    C++指针学习(1)
    C++头文件和实现(用复数类举例)
    从helloworld开始
    标准库string类型
    浅谈Lua的Coroutine协程的多"线程"并发模型
    关于闭包函数的概念和原理
    笔记
  • 原文地址:https://www.cnblogs.com/omgliyq/p/14414118.html
Copyright © 2011-2022 走看看