多线程核心技术 Chapter1

Posted tbricks24

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程核心技术 Chapter1相关的知识,希望对你有一定的参考价值。

多线程核心技术 技能基础Charpter1

本章需要着重掌握的是

  • 线程的启动
  • 如何使线程暂停
  • 如何使线程停止
  • 线程的优先级
  • 线程安全相关的问题

    1.1 进程和多线程的概念及多线程的优点

    1.2 使用多线程

    1.2.1 继承Thread类
    1.2.2 实现Runnable接口
    1.2.3 实例变量与线程安全
    1.2.4 留意i-- 与 System.out.println()的异常

    1.3 currentThread()方法

    1.4 isAlive()方法

    1.5 sleep()方法

    1.6 getId()方法

    1.7 停止线程(异常法)

  /**
    * stop()方法已经弃用,unsafe
     * interrupted()判断中断状态、并清除状态
     * isInterrupted()判断中断状态,不清除状态
     * interrupt() 停止线程的主要方法,但他不是真正终止一个正在运行的线程,只是在当前线程中打上一个停止标记,还需要加入一个判断才可以完成线程停止.
     * @author Hasee
     *
     */
public class Test11 {
        public static void main(String[] args) {
             try {
    //      Thread.currentThread().interrupt();
             MyThread11 thread = new MyThread11();
             thread.start();
             Thread.sleep(2000);
             thread.interrupt();
            System.out.println("是否停止1? =" + Thread.currentThread().isInterrupted());
            System.out.println("是否停止2? =" + Thread.currentThread().isInterrupted());
    
             }
             catch (InterruptedException e) {
             System.out.println("main catch");
             e.printStackTrace();
             }
            System.out.println("end!");
        }
    }
    
    class MyThread11 extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 500; i++) {
                System.out.println("i=" + (i + 1));
            }
        }
    }

以上可以看出当前线程是main,所以从未中断过.

    /**
     * 同样来看下段代码
     * 
     * @author Hasee
     *
     */
    public class Test14 {
        public static void main(String[] args) {
            try {
                MyThread11 thread = new MyThread11();
                thread.start();
                Thread.sleep(1000);// 暂停当前线程1s
                thread.interrupt();
                System.out.println("是否停止1? =" + thread.isInterrupted());
                System.out.println("是否停止2? =" + thread.isInterrupted());
            } catch (InterruptedException e) {
                System.out.println("main catch");
                e.printStackTrace();
            }
            System.out.println("end!");
    
        }
    }

可以看出,isInterrupted()并不清除状态.

/**
     * 在for循环中避免出现bug,可以抛出中断异常来处理
     * @author Hasee
     *
     */
    public class Test13 {
        public static void main(String[] args) {
            try {
                MyThread13 thread = new MyThread13();
                thread.start();
                Thread.sleep(2000);
                thread.interrupt();
            } catch (InterruptedException e) {
    
            }
        }
    }
    
    class MyThread13 extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                for (int i = 0; i < 500000; i++) {
                    if (this.isInterrupted()) {
                        System.out.println("isInterrupted = " + this.isInterrupted());
                        System.out.println("已经是停止状态了,我要退出.");
                        throw new InterruptedException();
                    }
                    System.out.println("i=" + (i + 1));
                }
                System.out.println("我在for下面");
            } catch (InterruptedException e) {
                System.out.println("进MyThread13类的run方法中的catch了!");
                e.printStackTrace();
            }
            System.out.println("end.");
        }
    }

如果不抛出异常的话,直接break会执行for循环之后的语句,没有达到中断的效果.这个叫做停止线程--异常法.

1.7.1在沉睡中停止
    /**
     * 在沉睡中停止
     * @author Hasee
     *
     */
    public class Test15 {
        public static void main(String[] args) {
            try {
                MyThread16 thread2 = new MyThread16();
                thread2.start();
                thread2.interrupt();
                System.out.println("end!");
                
                MyThread15 thread = new MyThread15();
                thread.start();
                Thread.sleep(200);
                thread.interrupt();
            } catch (InterruptedException e) {
                System.out.println("main catch");
            }
            System.out.println("end!");
        }
    }
    
    //主方法中先sleep再用interrupt()
    class MyThread15 extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                System.out.println("run begin");
                Thread.sleep(200000);
                System.out.println("run end");
            } catch (InterruptedException e) {
                System.out.println("在沉睡中被停止! 进入catch!" + this.isInterrupted());
                e.printStackTrace();
            }
        }
    }
    
    //
    class MyThread16 extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                for(int i = 0; i < 10000; i++) {
                    System.out.println("i=" + (i+1));
                }
                System.out.println("run begin");
                Thread.sleep(200000);
                System.out.println("run end");
            } catch (Exception e) {
                System.out.println("先停止,再遇到sleep!进入catch");
                e.printStackTrace();
            }
        }
    }

以上是在沉睡中停止,可以先sleep和后sleep

1.7.2 stop()暴力停止,已经弃用

使用stop()释放锁会给数据造成不一致性的结果.
示例如下:

public class TestStop1 {
        public static void main(String[] args) {
            try {
                SynchronizedObject object = new SynchronizedObject();
                MyThreadStop1 mts1 = new MyThreadStop1(object);
                mts1.start();
                Thread.sleep(500);
                mts1.stop();//强制停止,不建议在程序中用stop()
                System.out.println(object.getUsername() + " " + object.getPassword());
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class SynchronizedObject {
        private String username = "a";
        private String password = "aa";
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        synchronized public void printString(String username, String password) {
            try {
                this.username = username;
                Thread.sleep(100000);
                this.password = password;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    class MyThreadStop1 extends Thread {
        private SynchronizedObject object;
    
        public MyThreadStop1(SynchronizedObject object) {
            this.object = object;
        }
    
        @Override
        public void run() {
            super.run();
            object.printString("b", "bb");
        }
    }
1.7.3 使用return停止线程

就是直接判断isInterrupted()状态后进行return,建议还是使用抛异常来操作

1.8 暂停线程(线程可恢复)

1.8.1 suspend和resume方法的使用
  • 可用suspend来暂停线程
  • 可用resume来恢复线程

示例如下:

public class TestSuspend_Resume {
    public static void main(String[] args) {
            try {
                    Suspend_Resume_Thread thread = new Suspend_Resume_Thread();
                    thread.start();
                    Thread.sleep(5000);
                    // A段
                    thread.suspend();
                    System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
                    Thread.sleep(5000);
                    System.out.println("A= " + System.currentTimeMillis() + " i=" + thread.getI());
                    // B段
                    thread.resume();
                    Thread.sleep(5000);
                    // C段
                    thread.suspend();
                    System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
                    Thread.sleep(5000);
                    System.out.println("B= " + System.currentTimeMillis() + " i=" + thread.getI());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
class Suspend_Resume_Thread extends Thread {
    private long i = 0; 
    public long getI() {
                return i;       
    }
    public void setI(long i) {
                this.i = i;
    }
        
    @Override           
    public void run() {
                super.run();
                while (true)
                    i++;
            };
        }
1.8.2 suspend与resume方法的缺点——独占

造成公共的同步对象的独占,使得其他线程无法访问公共同步对象。
如下示例:

public class TestResume_Suspend2 {
        public static void main(String[] args) {
            try {
                final SynchronizedObject1 object = new SynchronizedObject1();
                Thread thread1 = new Thread() {
                    public void run() {
                        object.printString();
                    };
                };
                thread1.setName("a");
                thread1.start();
                Thread.sleep(1000);
                Thread thread2 = new Thread() {
                public void run() {
                        System.out.println("thread2启动了,但进入不了printString方法!,只打印1个begin");
                        System.out.println("因为printString()方法被a线程锁定并且永远suspend暂停了!");
                        object.printString();//不能再被访问
                    };
                };
                thread2.start();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("I love YJY");;
            }
        }
    }
    
    class SynchronizedObject1{
        synchronized public void printString() {
            System.out.println("begin");
            if(Thread.currentThread().getName().equals("a")) {
                System.out.println("a线程永远suspend了!");
                Thread.currentThread().suspend();
            }
        }
    }

以上代码即锁死了Object调用pringString()方法。
特别要注意System.out.println()方法是带同步锁的,如果内部suspend的话,同步锁没有被释放,会造成死锁。

suspend与resume方法的缺点——不同步

因为暂停而导致数据不同步。

    public class TestResume_Suspend3 {
        public static void main(String[] args) {
            try {
                final MyObject object = new MyObject();
                Thread thread1 = new Thread() {
                    public void run() {
                        object.setValue("a", "aa");
                    };
                };
                thread1.setName("a");
                thread1.start();
                Thread.sleep(500);
                Thread thread2 = new Thread() {
                    public void run() {
                        object.printUsernamePassword();
                    };
                };
                thread2.start();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                System.out.println("I love YJY");
    
            }
        }
    }
    
    class MyObject {
        private String username = "1";
        private String password = "11";
    
        public void setValue(String u, String p) {
            this.username = u;
            //如果当前线程名为a,则进行线程暂停
            if (Thread.currentThread().getName().equals("a")) {
                System.out.println("停止a线程!");
                Thread.currentThread().suspend();
            }
            this.password = p;
        }
        public void printUsernamePassword() {
            System.out.println(username + " " + password);
        }
    }

以上即为不同步的情况。

1.9 yield方法

该方法作用是放弃当前的cpu资源,将它让给其他的任务去占用cpu执行时间,但放弃的时间不确定。

public class TestYield {
        public static void main(String[] args) {
            YieldThread thread = new YieldThread();
            thread.start();
        }
    }
    class YieldThread extends Thread {
        @Override
        public void run() {
            long beginTime = System.currentTimeMillis();
            int count = 0;
            for (int i = 0; i < 5000000; i++) {
                Thread.yield();//将CPU让给其它资源导致最终执行完的速度变慢
                count = count + (i + 1);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("用时:" + (endTime - beginTime) + "毫秒!");
        }
    }

1.10 线程的优先级

  • 优先级较高的线程得到的CPU资源较多
  • 线程优先具有继承性---->比如A线程启动B线程,则B线程的优先级与A是一样的
  • 高优先级总是大部分先执行完,但不代表高优先级的线程总是全部先执行完
  • 当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关
  • 即优先级越高,CPU尽量将执行资源让给优先级高的线程,1-10,10是最高优先级
  • 优先级具有随机性,优先级较高的线程不一定每一次都先执行完

1.11 守护线程

Java中有两种线程,一种是用户线程,另外一种就是守护线程(Daemon线程)
典型的守护进程就是垃圾回收线程,当进程中没有非守护线程了,则垃圾回收线程也就没有存在的必要的。
GC就是典型的垃圾回收器。

总结

主要就是开篇的几个要点,然后对API的使用,以及Synchronized关键字的基本使用。






以上是关于多线程核心技术 Chapter1的主要内容,如果未能解决你的问题,请参考以下文章

java多线程编程核心技术怎么样

Java多线程具体解释

java核心技术-多线程之线程基础

多线程编程核心技术总结(读周志明书籍的总结)

多线程是啥

chapter1.高通量序列实验简介:设计与生物信息学分析