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));
            }
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/Tonyzczc/p/9995278.html