zoukankan      html  css  js  c++  java
  • Java基础--并发编程

    JAVA并发程序设计第一步:了解Java虚拟机提供的API操作,以及线程基本概念的操作:

    1:定义线程 -- 继承Thread类和实现Runnable方法

     1 /**
     2      * 定义线程 1:继承Thread类,方法、形式如下
     3      */
     4     public static class T1 extends Thread{
     5         @Override
     6         public void run() {
     7             System.out.println("Threads.T1.run()");
     8         }
     9 
    10         public static void main(String[] args) {
    11             /**
    12              * 启动线程:只需要使用new关键字创建一个线程对象,并且将它 start()起来即可。
    13              */
    14             T1 t1 = new T1();
    15             Thread thread = new Thread(t1);
    16             thread.start();
    17             T2 t2 = new T2();
    18             Thread thread2 = new Thread(t2);
    19             thread2.start();
    20         }
    21     }
    22     /**
    23      *定义线程 实现runnable接口,方法、形式如下
    24      */
    25     public static class T2 implements Runnable{
    26 
    27         public void run() {
    28             System.out.println("Threads.t2.run()");
    29         }
    30 
    31     }

    2:线程终止--  不要用 API 提供的 stop() , stop太暴力,应自己写逻辑实现

    public static class StopThread implements Runnable{
            volatile boolean stopme = false;
            public void stopeMe(){
                stopme = true;
            }
            public void run() {
                while (true) {
                    if (stopme) {
                        System.out.println("exit by stop me");
                        break;
                    }
                }
            }
        }

    3:线程中断

        /**
         *  线程中断
         *  public void Thread.interrupt()   //中断线程
         *  Public void boolean Thread.isInterrupted()   //判断线程是否被中断
         *  Public static boolean Thread.interrupted()   //判断是否被中断,并请除当前中断状态
         */
        public static class InterrupThread implements Runnable{
    
            public void run() {
                while(true){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                    System.out.println("Thread running");
                }
            }
    
            public static void main(String[] args) {
                /**
                 * 启动线程:只需要使用new关键字创建一个线程对象,并且将它start()起来即可。
                 */
                InterrupThread interrupThread = new InterrupThread();
                Thread thread =  new Thread(interrupThread);
                thread.start();
    //            Thread.sleep(1000);
                /**
                 * thread 会 产生中断,但是并没有处理中断,遇到 sleep 抛出异常
                 * 当程序出现 wait 和sleep 的时候,中断会被忽略掉
                 * 如果线程运行到了sleep()代码段,主程序中断线程,线程这这时候抛出异常,
                 * 进入catch的异常处理。在catch代码段中,由于捕获到了中断,我们可以立即退出线程。
                 * 在这里我们并没有这么做,因为也许在这段代码中,我们还必须进行后续处理,保证数据的一致性和完整性,
                 * 因此,执行了Thread.interrupt()方法在次中断自己,设置中断标志位。
                 */
                thread.interrupt();
                System.out.println(thread.isInterrupted());
            }
        }

    4:等待和通知

    public class WaitAndNotify {
        /**
         * JDK提供了两个非常重要的接口,线程等待wait()方法和线程通知方法notify()。这两个方法不是在Thread类中的
         * object.notifyAll()方法,他会唤醒等待队列中的所有线程。
         */
        final static Object object = new Object();
        public static class MyThread_1 extends Thread{
            @Override
            public void run(){
                synchronized (object) {
                    System.out.println(System.currentTimeMillis()+"T1 start");
                    try {
                        System.out.println(System.currentTimeMillis()+"T1 wait");
                        object.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(System.currentTimeMillis()+"T1 end");
                }
            }
        }
        public static class MyThread_2 extends Thread {
            @Override
            public void run() {
                synchronized (object) {
                    System.out.println(System.currentTimeMillis() + "T2 start and notify");
                    object.notify();
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            Thread t1 = new MyThread_1();
            Thread t2 = new MyThread_2();
            t1.start();
            t2.start();
    
        }
    }

    5:volatile关键字解析

    public class VolatileApp {
        /**
         * 这里的 ready  和 number 相当于 被 volatile 修饰的变量
         * volatile来声明一个变量时,就等于告诉了虚拟机,这个变量极有可能会被某些程序或者是线程修改。
         * 为了确保这个变量被修改后,应用程序范围内所有线程都能看到这个改动,虚拟机就必须采取一些特殊的手段,保证这个变量的可见性等特点。
         */
        private static boolean ready;
        private static int number;
        public static void main(String[] args) throws InterruptedException {
            MyThread myThread =   new MyThread();
            Thread thread = new Thread(myThread);
            thread.start();
            thread.sleep(1000);
            ready = false;
            number = 100;
            thread.sleep(2000);
        }
        public static class MyThread implements Runnable{
    
            public void run() {
                while(!ready)
                    System.out.println(number);
            }
        }
    }

    6:线程组概念

    public class ThreadGroupApp {
        /**
         * 构造方法:
         *
         * ThreadGroup(String name):以指定线程组名字来创建新线程组
         *
         * ThreadGroup(ThreadGroup parent,String name):以指定的名字、指定的父线程组来创建一个新线程组。
         *
         * 常用操作方法:
         *
         * · int activeCount():获取线程组中活动线程的数量
         *
         * · interrupt():中断线程组中所有线程
         *
         * · isDaemon():是否为后台线程组
         *
         * · setDaemon(boolean daemon):设置为后台线程组
         *
         * · setMaxPriority(int pri):设置线程组的最高优先级
         *
         *   线程都是在创造的同时加入线程组中,然后才start。上述代码展示了线程组的两个重要功能,
         *
         *   activeCount()可以获得活动线程的总数,但由于线程是动态的,所以这个值是一个预估值,
         *
         *   list()可以打印这个线程组中所有的线程信息,对调试有一定帮助。
         */
        public static void main(String[] args) {
            ThreadGroup threadGroup = new ThreadGroup("ThreadGroupApp");
            MyThread myThread_1 = new MyThread(threadGroup,"myThread_1");
            MyThread myThread_2 = new MyThread(threadGroup,"myThread_2");
            myThread_1.setDaemon(true);//设置守护线程 ,必须在start 之前执行
            myThread_1.setPriority(1);//设置线程优先级  1-10
            myThread_1.start();
            myThread_2.start();
            System.out.println(threadGroup.activeCount());
            threadGroup.list();
        }
        public static class MyThread extends Thread{
            public MyThread(String name){
                super(name);
            }
            public MyThread(ThreadGroup group,String name){
                super(group, name);
            }
            @Override
            public void run() {
                super.run();
            }
        }
    }

    7:synchronized 线程安全概念

    /**
     * 线程安全 synchronized
     * 除了线程同步,确保线程安全, synchronized 确保线程之间可见、有序
     * 从可见性的角度上讲,synchronized完全可以代替volatile的功能,只是使用上没有那么方便。就有序性而言,
     * 由于synchronized每一次只有一个线程可以访问同步块,因此,无论同步块内的代码如何被乱序执行,只要保证串行语义一致,那么执行的结果总是一样的。
     * 换而言之,被synchronized限制的多个线程是串行执行的。
     */
    public class ThreadSafeApp {
        public static int number;
    
        public static void main(String[] args) throws InterruptedException {
            AddThread addThread_1 = new AddThread();
            AddThread addThread_2 = new AddThread();
            Thread thread_1 = new Thread(addThread_1);
            Thread thread_2 = new Thread(addThread_2);
            thread_1.start();
            thread_2.start();
            thread_1.join();
            thread_2.join(); // 等待线程结束
            System.out.println(number);
        }
        public static class AddThread implements  Runnable{
            /**
             * 牵扯到内存模型,每一个类 new 的时候会生成方法区,在堆中独立的空间所以声明synchronized 同步方法只是在这个类中构造独立,那么两个内存空间还是相互影响
             * 数据不一致 -- 解决办法为:设置成静态
             */
            public static synchronized  void add(){
                number++;
            }
            public void run() {
    //            synchronized (AddThread.class) {
                    for (int i = 0; i < 10000; i++) {
    //                    number++;
                        add();
                    }
                }
    //        }
        }
    }

    8:重入锁

    public class LockApp {
        public static ReentrantLock Lock = new ReentrantLock();
        public static int Count = 0;
    
        public static void main(String[] args) throws InterruptedException {
            ThreadLock t1 = new ThreadLock();
            ThreadLock t2 = new ThreadLock();
            t1.start();t2.start();
            t1.join();t2.join();
            System.out.println(Count);
    
        }
        public static class ThreadLock extends Thread{
            @Override
            public void run() {
                for(int i=0;i<10000;i++) {
                    /**
                     * 必须手动指定何时加锁 ,何时释放锁。也正是因为这样,
                     * 重入锁逻辑控制远远要好于synchronized。
                     * 但值得注意的是,在退出零界区时,必须记得要释放锁,否者永远没有机会再访问零界区了,会造成其线程的饥饿甚至是死锁。
                     * 针对 lock() 可以多次调用! 但是必须释放
                     */
                    Lock.lock();
                    Count++;
                    Lock.unlock();
                }
            }
        }
    }

    9:lockInterruptibly 重入锁的中断

    /**
     * 重入锁的中断 lockInterruptibly
     * 优先考虑响应中断,而不是响应锁的普通获取或重入获取。
     */
    public class ThreadInterruptibilyApp {
        public static ReentrantLock Lock1 = new ReentrantLock();
        public static ReentrantLock Lock2 = new ReentrantLock();
    
        public static void main(String[] args) throws InterruptedException {
            MyThread t1 = new MyThread(1);
            MyThread t2 = new MyThread(2);
            t1.start();
            t2.start();
            Thread.sleep(3000);
            t2.interrupt();
            /**
             *   在t1和t2线程start后,主线程main进入休眠,此时t1和t2线程处于死锁状态,
             *   然后主线程main中断t2线程,
             *   故t2会放弃对lock1的请求,同时释放lock2。这个操作使得t1可以获得lock2从而继续执行下去。
             *   那么,完成工作的只有t1 ,t2 是直接放弃推出,释放资源
             */
        }
    
        public static class MyThread extends Thread{
            int flag;
            MyThread(int flag) {
                this.flag = flag;
    
            }
    
            @Override
            public void run() {
                try{
                    if(flag == 1){
                        try {
                            Lock1.lockInterruptibly();
                            Thread.sleep(1000);
                            Lock2.lockInterruptibly();
                            System.out.println(flag+"号线程:完成工作");
                        } catch (InterruptedException e) {}
                    }
                    else if(flag == 2){
                        try {
                            Lock2.lockInterruptibly();
                            Thread.sleep(1000);
                            Lock1.lockInterruptibly();
                            System.out.println(flag+"号线程:完成工作");
                        } catch (InterruptedException e) {}
                    }
                }finally{
                    //中断响应
                    if(Lock1.isHeldByCurrentThread()){
                        Lock1.unlock();
                        System.out.println(flag+":Lock1 interrupted unlock");
                    }
                    if(Lock2.isHeldByCurrentThread()){
                        Lock2.unlock();
                        System.out.println(flag+":Lock2 interrupted unlock");
                    }
                    System.out.println(flag+"号线程退出");
                }
            }
        }
    }

    10:Map、ArrayList、Vector、ConcurrenHashMap 线程安全测试

    public class ThreadErrorApp {
        public static Map<String,String> threadMap = new HashMap<String, String>();
        public static ArrayList<Integer> threadArrayList = new ArrayList<Integer>();
        public static Vector<Integer> threadVector = new Vector<Integer>();
        public static void main(String[] args) throws InterruptedException {
    //        MyThread myThread_1 = new MyThread();
    //        MyThread myThread_2 = new MyThread();
    //        Thread thread_1 = new Thread(myThread_1);
    //        Thread thread_2 = new Thread(myThread_2);
    //        thread_1.start();
    //        thread_2.start();
    //        thread_1.join();
    //        thread_2.join();
    //        System.out.println(threadVector.size());
            MyThreadMap myThread_1 = new MyThreadMap();
            MyThreadMap myThread_2 = new MyThreadMap();
            Thread thread_1 = new Thread(myThread_1);
            Thread thread_2 = new Thread(myThread_2);
            thread_1.start();
            thread_2.start();
            thread_1.join();
            thread_2.join();
            System.out.println(threadMap.size());
        }
    
        /**
         * 1: 报错java.lang.ArrayIndexOutOfBoundsException 因为内存一致性 遭到破坏,产生越界问题
         * 2:size 小于 20000
         * 解决办法 使用Vector
         */
        public static class MyThread extends Thread {
            @Override
            public void run() {
                for (int i=0;i<10000;i++){
    //                threadArrayList.add(i);
                    threadVector.add(i);
                }
            }
        }
    
        /**
         * 程序正常结束,但结果不符合预期,而是一个小于100000的数字。
         * 使用 ConcurrenHashMap 代替
         */
        public  static class MyThreadMap extends Thread{
            @Override
            public void run() {
                for (int i=0;i<10000;i++){
                    threadMap.put(Integer.toString(i),Integer.toString(i));
                }
            }
        }
    }
  • 相关阅读:
    Python容器(zz)
    [Violet]蒲公英 分块
    [JSOI2008]火星人 hash+splay
    [USACO08DEC]拍头Patting Heads 水题
    [国家集训队]整数的lqp拆分 数学推导 打表找规律
    [HNOI2008]水平可见直线 单调栈
    [LNOI2014]LCA 树链剖分 离线 前缀和 思维题
    [SCOI2008]着色方案 递推 记忆化搜索
    [NOI2010]海拔 平面图转对偶图 最小割
    [NOI2008]志愿者招募 网络流 建模
  • 原文地址:https://www.cnblogs.com/Tonyzczc/p/9995278.html
Copyright © 2011-2022 走看看