• Java高并发之线程基本操作


    结合上一篇同步异步,这篇理解线程操作。

    1、新建线程。不止thread和runnable,Callable和Future了解一下

    package com.thread;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    
    /**
     * 线程启动
     * @author Administrator
     *
     */
    public class StartThreadTest extends Thread{
    
        @Override
        public void run(){
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"i:"+i);
            }
        }
        
        public static void main(String[] args) throws InterruptedException {
            //继承 Thread 类的线程启动方式
            StartThreadTest test = new StartThreadTest();
            StartThreadTest test2 = new StartThreadTest();
            System.out.println("开始执行线程1......");
            test.start();test2.start();
            test.join();test2.join();  //join方法会让main线程等待test、test2线程执行完,如果对执行结果不感冒,则不用join
            System.out.println("结束执行线程1......");
        }
        //******************************************************************************************************
        static class startThread2 implements Runnable{
    
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("i:"+i);
                }
            }
            
            public static void main(String[] args) {
                //实现 Runnable 接口的线程启动方式
                startThread2 thread2 = new startThread2();
                Thread t = new Thread(thread2);
                t.start();
            }
        }
        //******************************************************************************************************
        /**
         * Callable 用于获取线程执行结果
         *     多个Callable耗时是每个线程的总耗时
         * @author Administrator
         *
         */
        static class startThread3 implements Callable<String>{
    
            @Override
            public String call() throws Exception {
                int result = 0;
                for (int i = 0; i < 3; i++) {
                    Thread.sleep(1000);
                    result += i;
                }
                return String.valueOf(result);
            }
            
            public static void main(String[] args) throws Exception {
                SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
                System.out.println("开始时间:"+format.format(new Date()));
                
                Callable<String> call = new Callable<String>() {
                    
                    @Override
                    public String call() throws Exception {
                        int result = 0;
                        for (int i = 0; i < 5; i++) {
                            Thread.sleep(1000);
                            result += i;
                        }
                        return String.valueOf(result);
                    }
                };
                ExecutorService service = Executors.newSingleThreadExecutor();
                Future<String> f = service.submit(call);
                System.out.println(f.get());
                service.shutdown();
                System.out.println("时间1:"+format.format(new Date()));
                //实现 Callable 接口的线程启动方式
                startThread3 thread3 = new startThread3();
                System.out.println("开始执行线程......");
                String result = thread3.call();
                System.out.println("结束执行线程。result:"+result);  //result:3 【线程执行完获取结果,会阻塞当前线程】
                System.out.println("时间2:"+format.format(new Date()));
                
                //开始时间:05:04:21
                //10
                //时间1:05:04:26
                //开始执行线程......
                //结束执行线程。result:3
                //时间2:05:04:29
    
            }
        }
        //******************************************************************************************************
        /**
         * Future 用于获取异步线程的结果,总耗时是最长耗时的线程
         * @author Administrator
         *
         */
        static class startThread4 {
            public static void main(String[] args) throws InterruptedException, ExecutionException {
                SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
                System.out.println("开始时间:"+format.format(new Date()));
                
                //操作1:耗时3秒
                FutureTask<String> futureTask = new FutureTask<>(new startThread3());
                new Thread(futureTask).start();
                
                //操作2:耗时5秒
                Callable<String> call = new Callable<String>() {
                    
                    @Override
                    public String call() throws Exception {
                        int result = 0;
                        for (int i = 0; i < 5; i++) {
                            Thread.sleep(1000);
                            result += i;
                        }
                        return String.valueOf(result);
                    }
                };
                FutureTask<String> futureTask2 = new FutureTask<>(call);
                new Thread(futureTask2).start();
                
                System.out.println("操作1返回:"+futureTask.get());
                System.out.println("操作2返回:"+futureTask2.get());
                
                System.out.println("结束时间:"+format.format(new Date()));
                
                //开始时间:04:50:53
                //操作1返回:3
                //操作2返回:10
                //结束时间:04:50:58
            }
        }
    }
    View Code

    2、停止线程。volatile和interrupt各显神通

    package com.thread;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * 关闭线程
     * @author Administrator
     *
     */
    public class StopThreadTest extends Thread {
    
        static int i = 0;
        static int j = 0;
    
        @Override
        public void run() {
            //同步操作确保i,j都自增1
            synchronized (this) {
                i++;
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                j++;
            }
        }
        
        public static void main(String[] args) throws InterruptedException {
            StopThreadTest test = new StopThreadTest();
            test.start();
            Thread.sleep(1000);
            //Thread.stop():强制关闭对象获取的锁,破坏线程数据安全
            test.stop();
            test.join();
            System.out.println("i:"+i+";j:"+j);  //i:1;j:0
            
        }
        
        static class volatileStopThreadTest extends Thread{
            
            volatile boolean exitFlag = false;  //volatile确保可见性
            static SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
            
            @Override
            public void run() {
                System.out.println("run线程开始时间:"+format.format(new Date()));
                while(!exitFlag){
                    System.out.println("run方法进入时间:"+format.format(new Date()));
                    //同步操作确保i,j都自增1
                    synchronized (this) {
                        i++;
                        try {
                            Thread.sleep(10000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        j++;
                    }
                }
                System.out.println("run线程结束时间:"+format.format(new Date()));
            }
            
            public static void main(String[] args) throws InterruptedException {
                System.out.println("主线程开始时间:"+format.format(new Date()));
                volatileStopThreadTest test = new volatileStopThreadTest();
                test.start();
                Thread.sleep(1000);
                System.out.println("主线程休眠1秒:"+format.format(new Date()));
                test.exitFlag = true;
                test.join();
                System.out.println("i:"+i+";j:"+j);
                
                //主线程开始时间:05:17:03
                //run线程开始时间:05:17:03
                //run方法进入时间:05:17:03
                //主线程休眠1秒:05:17:04   【标志位exitFlag改了,run方法依然在执行,只是下次竞争到锁都不执行run】
                //run线程结束时间:05:17:13
                //i:1;j:1  【确保了线程数据安全】
    
            }
        }
        
        static class interruptStopThreadTest extends Thread{
            
            static SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
            
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"-线程进入run开始时间:"+format.format(new Date()));
                while(true){
                    //判断线程是否已经被中断,如果被中断,则下次竞争时直接退出
                    if(Thread.currentThread().isInterrupted()){
                        System.out.println(Thread.currentThread().getName()+"-线程已被中断......,中断时间:"+format.format(new Date()));
                        //退出while循环
                        break;
                    }
                    //同步操作确保i,j都自增1
                    synchronized (this) {
                        i++;
                        try {
                            Thread.sleep(10000);
                            System.out.println(Thread.currentThread().getName()+"-线程休眠10秒......");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            System.out.println("中断标志:"+Thread.currentThread().isInterrupted());
                            //阻塞过程中被中断,test.interrupt()方法设置的中断标识会立刻变成false,需要重新设置中断标识
                            Thread.currentThread().interrupt();
                            System.out.println(Thread.currentThread().getName()+"-线程被中断了!");
                        }
                        j++;
                    }
                    //打印:
                    //Thread-0-线程进入run开始时间:10:01:34
                    //java.lang.InterruptedException: sleep interrupted
                    //    at java.lang.Thread.sleep(Native Method)
                    //    at com.thread.StopThreadTest$interruptStopThreadTest.run(StopThreadTest.java:103)
                    //中断标志:false
                    //Thread-0-线程被中断了!
                    //Thread-0-线程已被中断......,中断时间:10:01:36
                    //i:1;j:1  【线程数据安全】
    
    //                synchronized (this) {
    //                    i++;
    //                    try {
    //                        for (int z = 0; z < 10; z++) {
    //                            if(z==9){
    //                                int a = 1/0;
    //                                System.out.println("模拟异常");
    //                            }
    //                        }
    //                        Thread.sleep(5000); //异常后的语句不会执行
    //                    } catch (Exception e) {
    //                        e.printStackTrace();
    //                        //线程执行过程中抛出了异常,通过设置中断标识,控制下次竞争
    //                        Thread.currentThread().interrupt();
    //                        System.out.println(Thread.currentThread().getName()+"-线程被中断了!");
    //                    }
    //                    j++;
    //                }
                    //打印:
                    //Thread-0-线程进入run开始时间:10:08:43
                    //Thread-0-线程被中断了!
                    //java.lang.ArithmeticException: / by zeroThread-0-线程已被中断......,中断时间:10:08:43
    
                    //    at com.thread.StopThreadTest$interruptStopThreadTest.run(StopThreadTest.java:126)
                    //i:1;j:1  【线程数据安全】
    
                }
            }
            
            public static void main(String[] args) throws InterruptedException {
                interruptStopThreadTest test = new interruptStopThreadTest();
                test.start();
                Thread.sleep(2000);
                test.interrupt();  //中断线程 【设置中断标志,通过isInterrupted()控制竞争】
                test.join();
                System.out.println("i:"+i+";j:"+j);
            }
        }
    }
    View Code

     3、线程挂起和继续执行。suspend和resume谨慎使用

    package com.thread;
    
    /**
     * 线程挂起与继续执行
     *     不推荐用:
     *         1、锁得不到释放,如果第二个线程先于第一个线程执行resume之前执行start,将造成锁永久等待
     *         2、锁住的共享资源如果暗含同步方法,将导致其他线程使用该同步方法等待
     * @author Administrator
     *
     */
    public class SuspendANDresumeThreadTest extends Thread{
    
        volatile int i = 0;
        
        @Override
        public void run(){
            while(true){
                synchronized(this){
                    i++;
                    System.out.println(Thread.currentThread().getName()+"-i:"+i);
                }
            }
        }
        
        public static void main(String[] args) throws InterruptedException {
            SuspendANDresumeThreadTest test = new SuspendANDresumeThreadTest();
            SuspendANDresumeThreadTest test2 = new SuspendANDresumeThreadTest();
            test.start();
            Thread.sleep(1);
            //test线程挂起后,占有的锁不会释放,导致test2线程一直处于阻塞态
            test.suspend();
    //        test2.start();
    //        test.join();
            //另外:查看println源码得知该方法是同步方法,在test占有锁的同时,导致println()也被占有,从而main线程无法执行下面的打印语句
            System.out.println("该句无法打印!");
            
        }
    }
    View Code

    4、等待线程结束和谦让。join和yield

    package com.thread;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    /**
     * join:当前线程等待执行join的线程执行完
     * yield:执行yield的线程让出占用的锁
     * @author Administrator
     *
     */
    public class JoinANDyieldThreadTest extends Thread{
    
        static SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
        
        @Override
        public void run(){
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName()+"-i:"+i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        
        public static void main(String[] args) throws InterruptedException {
            JoinANDyieldThreadTest test = new JoinANDyieldThreadTest();
            JoinANDyieldThreadTest test2 = new JoinANDyieldThreadTest();
            
    //        test.start();
    //        Thread.sleep(3000);
    //        test.yield();
    //        test2.start();
            
            //Thread-0-i:0
            //Thread-0-i:1
            //Thread-0-i:2  
            //Thread-0-i:3  【执行test.yield()后,test依然抢到了锁】
            //Thread-1-i:0
            //Thread-1-i:1
            //Thread-0-i:4
            
            test.setPriority(MIN_PRIORITY);  //低优先级
            test2.setPriority(MAX_PRIORITY);  //高优先级
            System.out.println("开始时间:"+format.format(new Date()));
            test.start();
            Thread.sleep(3000);
            test.yield();
            test2.start();
            test.join();
            test2.join();  //确保下面的打印在test和test2执行完后执行
            System.out.println("结束时间:"+format.format(new Date()));
            //Thread-0-i:0
            //Thread-0-i:1
            //Thread-0-i:2
            //Thread-0-i:3  【test设置低优先级依然抢到了锁】
            //Thread-1-i:0
            //Thread-0-i:4
            //Thread-1-i:1
            //Thread-0-i:5
            
        }
    }
    View Code

    5、线程等待和唤醒。wait和notify

    package com.thread;
    
    /**
     * wait 和 notify 设计生产者与消费者模式
     *     锁的选用:线程共享的变量
     *     wait 和 notify时机的运用,确保先生产后消费
     * @author Administrator
     *
     */
    public class WaitANDnotifyThreadTest {
        private static Integer count = 0; // 数据仓库计数
        private final static Integer FULL = 5; // 数据仓库最大存储量
        private static String lock = "lock"; // 锁标识
        // Object obj = new Object();  //锁标识
    
        public static void main(String[] args) {
            new Thread(new Producer(), "product1").start();
            new Thread(new Consumer(), "consumer1").start();
            new Thread(new Producer(), "product2").start();
            new Thread(new Consumer(), "consumer2").start();
        }
    
        // 生产者
        static class Producer implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    synchronized (lock) {
                        while (count == FULL) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        count++;
                        System.out.println(Thread.currentThread().getName() + "-produce:: " + count);
                        // 唤醒lock锁上的所有线程
                        lock.notifyAll();
                    }
                }
            }
        }
    
        // 消费者
        static class Consumer implements Runnable {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e1) {
                        e1.printStackTrace();
                    }
                    synchronized (lock) {
                        // 如果首次消费者竞争得到锁,进入后等待
                        while (count == 0) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName() + "-consume:: " + count);
                        lock.notifyAll();
                    }
                }
            }
        }
    }
    View Code
  • 相关阅读:
    Django-ORM
    Django-路由系统
    Django-(Request对象和Response对象)
    Django-(CBV和FBV)
    批量设置模板中的时间格式
    Django模板语言-(母板、组件、静态文件相关、simple_tag、inclusion_tag)
    yii2csrf攻击
    centos6更改密码
    ide vscode安装
    xshell配色方案
  • 原文地址:https://www.cnblogs.com/x-jingxin/p/10319775.html
Copyright © 2020-2023  润新知