多线程核心技术 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关键字的基本使用。

原文地址:https://www.cnblogs.com/Tbricks24/p/9815602.html

时间: 2024-11-02 02:43:09

多线程核心技术 Chapter1的相关文章

java多线程核心技术梳理(附源码)

java多线程核心技术梳理(附源码) java多线程核心技术梳理附源码 写在前面 java多线程 对象及变量的并发访问 线程间通信 Lock的使用 定时器 单例模式与多线程 拾遗补增 参考资料 本文对多线程基础知识进行梳理,主要包括多线程的基本使用,对象及变量的并发访问,线程间通信,lock的使用,定时器,单例模式,以及线程状态与线程组. 写在前面 花了一周时间阅读<java多线程编程核心技术>(高洪岩 著),本文算是此书的整理归纳,书中几乎所有示例,我都亲手敲了一遍,并上传到了我的githu

Java多线程核心技术(五)单例模式与多线程

本文只需要考虑一件事:如何使单例模式遇到多线程是安全的.正确的 1.立即加载 / "饿汉模式" 什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接 new 实例化. public class MyObject { private static MyObject myObject = new MyObject(); public MyObject(){ } public static MyObject getInstance(){ return myObj

四、java多线程核心技术——synchronized同步方法与synchronized同步快

一.synchronized同步方法 论:"线程安全"与"非线程安全"是多线程的经典问题.synchronized()方法就是解决非线程安全的. 1.方法内的变量为线程安全 public void addI(String username) { try { int num = 0; \\方法内的变量为线程安全 if (username.equals("a")) { num = 100; System.out.println("a set

Java多线程核心技术读书摘要

Chapter1: 进程是操作系统管理的基本单元,线程是CPU调到的基本单元. 调用myThread.run()方法,JVM不会生成新的线程,myThread.start()方法调用两次JVM会报错. sleep(int t)方法是Thread类的方法,让this.currentThread()在t ms内休眠,不释放琐. 线程的停止有三个方法:①thread.stop()对于某些非原子操作会造成数据不一致②try catch+InterruptException+thread.interrup

三、java多线程核心技术(笔记)——线程的优先级

概论: 在操作系统中,线程可以划分优先级,优先级高的获得的CPU资源较多,也就是CPU优先执行优先级较高的线程.在JAVA中线程的优先级 分1~~10个10个等级.大于或者小于会报异常. 一.线程优先级具有继承性 A 线程启动 B线程,则线程B的优先级与A的是一样的.. public class MyThread1 extends Thread { @Override public void run() { System.out.println("MyThread1 run priority=&

java多线程系列(三)

等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解能让知识更加简单易懂. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知机制 java多线程系列(四)之ReentrantLock的使用 非等待通知 public void run() { try {

java多线程系列(一)

java多线程技能 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解能让知识更加简单易懂. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知机制 java多线程系列(四)之ReentrantLock的使用 并发历史 在没有操作系统的时候,一台计算机只执行一个程序,

java多线程系列(四)

Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解能让知识更加简单易懂. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知机制 java多线程系列(四)之ReentrantLock的使用 ReentrantLock(重入锁) public class

java多线程系列(二)

对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解能让知识更加简单易懂. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知机制 java多线程系列(四)之ReentrantLock的使用 线程安全 线程安全就是多线程访问时,采用了加锁机制,当一个