美文网首页码农的世界程序员
java进阶(二):多线程

java进阶(二):多线程

作者: 丁俊杰_ | 来源:发表于2018-10-02 21:56 被阅读4次

1、多线程的目的

即“最大限度的利用CPU资源”,当某一线程的处理不需要占用CPU而只和I/O等资源打交道时,让需要占用CPU资源的其他线程有机会获得CPU资源。

2、创建线程

方法一:
通过继承Thread类创建线程

  • 普通线程如果继承自Thread类,就成为了一个线程类,并可以通过该类的start方法来启动线程,执行线程代码。
    *Thread类的子类可以直接实例化,但在子类中必须覆盖run方法才能真正运行线程代码。
class MyThread extends Thread {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Thread myThread1 = new MyThread();     // 创建一个新的线程  myThread1  此线程进入新建状态
                Thread myThread2 = new MyThread();     // 创建一个新的线程 myThread2 此线程进入新建状态
                myThread1.start();                     // 调用start()方法使得线程进入就绪状态
                myThread2.start();                     // 调用start()方法使得线程进入就绪状态
            }
        }
    }
}

方法二:
通过实现Runnable接口创建线程

  • 实现Runnable接口的类必须借助Thread类才能创建线程。通过Runnable接口创建线程分为两步:
    1、创建实现Runnable接口的类的实例。
    2、创建一个Thread类对象,将第一步得到的实例作为参数传入Thread类的构造方法。
  • 通过Tread类的start方法启动线程。
class MyRunnable implements Runnable {
    private int i = 0;
    @Override
    public void run() {
        for (i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

public class ThreadTest {

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            if (i == 30) {
                Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
                Thread thread1 = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程
                Thread thread2 = new Thread(myRunnable);
                thread1.start(); // 调用start()方法使得线程进入就绪状态
                thread2.start();
            }
        }
    }
}

当然,还可以直接使用匿名内部类,方法十分简便,仅需重写run方法,例如:

/*
 * 匿名内部类的格式:
 */
public class ThreadDemo {
    public static void main(String[] args) {
        // 继承thread类实现多线程
        new Thread() {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + "--"
                            + x);
                }
            }
        }.start();
        ;

        // 实现runnable借口,创建多线程并启动
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + "--"
                            + x);
                }
            }
        }) {
        }.start();

        // 更有难度的,在Thread匿名内部类的里面再一次重写run方法
        //在实际运行时的结果是 hello+x。以thread的run方法为准。但是此处无意义
        new Thread(new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                for (int x = 0; x < 100; x++) {
                    System.out.println("java" + "--" + x);
                }

            }
        }) {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("hello" + "--" + x);
                }
            }
        }.start();
    }
}

3、线程完整生命周期

生命周期


4、线程同步

线程同步是为了防止多个线程访问一个数据对象时,对数据造成破坏。

注意:用synchronized关键字声明的静态方法,同时只能被一个执行线程访问,但是其他线程可以访问这个对象的非静态方法。即:两个线程可以同时访问一个对象的两个不同的synchronized方法,其中一个是静态方法,一个是非静态方法。
//示例
public synchronized void addAmount(double amount) {
}

synchronized(this){
}

5、线程通信

假设有这么一个问题,要求编写两个线程,一个线程打印125,另一个线程打印字母AZ,打印顺序为12A34B56C……5152Z,这就要求使用线程间的通信,解决的方法有以下几种:

  • 使用一个共享变量控制,利用最基本的synchronized、notify、wait
public class MethodOne {
    private final ThreadToGo threadToGo = new ThreadToGo();
    public Runnable newThreadOne() {
        final String[] inputArr = Helper.buildNoArr(52);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                try {
                    for (int i = 0; i < arr.length; i=i+2) {
                        synchronized (threadToGo) {
                            while (threadToGo.value == 2)
                                threadToGo.wait();
                            Helper.print(arr[i], arr[i + 1]);
                            threadToGo.value = 2;
                            threadToGo.notify();
                        }
                    }
                } catch (InterruptedException e) {
                    System.out.println("Oops...");
                }
            }
        };
    }
    public Runnable newThreadTwo() {
        final String[] inputArr = Helper.buildCharArr(26);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                try {
                    for (int i = 0; i < arr.length; i++) {
                        synchronized (threadToGo) {
                            while (threadToGo.value == 1)
                                threadToGo.wait();
                            Helper.print(arr[i]);
                            threadToGo.value = 1;
                            threadToGo.notify();
                        }
                    }
                } catch (InterruptedException e) {
                    System.out.println("Oops...");
                }
            }
        };
    }
    class ThreadToGo {
        int value = 1;
    }
    public static void main(String args[]) throws InterruptedException {
        MethodOne one = new MethodOne();
        Helper.instance.run(one.newThreadOne());
        Helper.instance.run(one.newThreadTwo());
        Helper.instance.shutdown();
    }
}
  • 利用volatile关键字
    volatile修饰的变量值直接存在main memory里面,子线程对该变量的读写直接写入main memory,而不是像其它变量一样在local thread里面产生一份copy。volatile能保证所修饰的变量对于多个线程可见性,即只要被修改,其它线程读到的一定是最新的值。
public class MethodThree {
    private volatile ThreadToGo threadToGo = new ThreadToGo();
    class ThreadToGo {
        int value = 1;
    }
    public Runnable newThreadOne() {
        final String[] inputArr = Helper.buildNoArr(52);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                for (int i = 0; i < arr.length; i=i+2) {
                    while(threadToGo.value==2){}
                    Helper.print(arr[i], arr[i + 1]);
                    threadToGo.value=2;
                }
            }
        };
    }
    public Runnable newThreadTwo() {
        final String[] inputArr = Helper.buildCharArr(26);
        return new Runnable() {
            private String[] arr = inputArr;
            public void run() {
                for (int i = 0; i < arr.length; i++) {
                    while(threadToGo.value==1){}
                    Helper.print(arr[i]);
                    threadToGo.value=1;
                }
            }
        };
    }
    public static void main(String args[]) throws InterruptedException {
        MethodThree three = new MethodThree();
        Helper.instance.run(three.newThreadOne());
        Helper.instance.run(three.newThreadTwo());
        Helper.instance.shutdown();
    }
}

6、线程死锁

死锁

相关文章

  • juc-Lock系列收藏

    Java多线程进阶(十一)—— J.U.C之locks框架:StampedLock

  • java进阶(二):多线程

    1、多线程的目的 即“最大限度的利用CPU资源”,当某一线程的处理不需要占用CPU而只和I/O等资源打交道时,让需...

  • 带你搞懂Java多线程(五)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三)带你搞懂Java多线程(四) ...

  • Java学习之_必备知识

    一、语言的入门及进阶 Java基础语法 OO编程思想 集合 IO 异常 泛型 反射 多线程 函数式 二、Web基础...

  • 带你搞懂Java多线程(六)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三)带你搞懂Java多线程(四)带...

  • 2018.05.13 杂谈

    《Java 并发编程实战》终于看完了,对于多线程有了一定的理解。多线程属于进阶技术。互联网行业充满了多线程和算...

  • 带你搞懂Java多线程(四)

    带你搞懂Java多线程(一)带你搞懂Java多线程(二)带你搞懂Java多线程(三) 什么是线程间的协作 线程之间...

  • 第十四周笔记分享

    Android开发高级进阶 一、多线程 二、new Thread()和ThreadPoolExceutor的区别:...

  • Java多线程学习(三)——synchronized(上)

    在前两节的《Java多线程学习(一)——多线程基础》和《Java多线程学习(二)——Thread类的方法介绍》中我...

  • 查漏补缺之 Java 篇

    Java 中的 Monitor机制 参考: Java 多线程(二)-Monitor synchronized 与 ...

网友评论

    本文标题:java进阶(二):多线程

    本文链接:https://www.haomeiwen.com/subject/gsiznftx.html