Java多线程与并发

文章目录

线程和进程的区别

JDK选择长期版本

线程和进程的区别

基础

线程进程、内核态用户态转换,为何转换、系统中断、内核态的多线程是如何通过轻量级实现的。结合自己理解融入到Java线程中

由来

区别

寄存器可被存储线程的局部变量,但是不能其他线程的相关变量

关系

代码查看主线程

Java采用单线程编程模型,

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-26 21:50
 */
public class CurrentThreadDemo {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
    }
}

thread.CurrentThreadDemo main

Thread中的start方法和run方法的区别

效果图

代码

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-26 22:17
 */
public class ThreadTest {
    public static void attack() {
        System.out.println("Fight");
        System.out.println("attack is :"+ Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                attack();
            }
        };
        System.out.println(Thread.currentThread().getName()); // main
//        t.run();  // main
        t.start(); // attack is :Thread-0
    }
}

main Fight attack is :Thread-0

分析源码

新线程由start创建

创建一个新的线程

创建一个线程去run方法名称

没有可比性run和star

Thread和Runnable是什么关系

本质

Thread类 Runnable接口

Runnable只有一个run抽象方法,说明此接口并不具备多线程的特性. 是依赖Thread里面的star方法在去调用run方法实现多线程

源码

代码演示

普通Thread.start()线程-效果图

多线程同时遍历

MyThread

package thread;

/**
 * 继承线程
 * @Author bennyrhys
 * @Date 2020-03-27 18:53
 */
public class MyThread extends Thread{
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("This is "+i+" Thread:" + this.name);
        }
    }
}
package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-27 18:56
 */
public class MyThreadMain {
    public static void main(String[] args) {
        new MyThread("THREAD1").start();
        new MyThread("THREAD2").start();
        new MyThread("THREAD3").start();
    }
}

通过Thread类启动Runnable多线程-效果图

MyRunnalbe

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-27 19:20
 */
public class MyRunnalbe implements Runnable{
    private String name;

    public MyRunnalbe(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("This is "+i+" Thread:" + this.name);
        }
    }
}

MyRunnableMain

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-27 19:21
 */
public class MyRunnableMain {
    public static void main(String[] args) {
        // 通过Thread的start()方法实现Runable的多线程
        MyRunnalbe thread1 = new MyRunnalbe("Thread1");
        Thread t1 = new Thread(thread1);
        t1.start();
        MyRunnalbe thread2 = new MyRunnalbe("Thread2");
        Thread t2 = new Thread(thread2);
        t2.start();
        MyRunnalbe thread3 = new MyRunnalbe("Thread3");
        Thread t3 = new Thread(thread3);
        t3.start();
    }
}

如何实现处理线程的返回值

如何给run()方法传参

跟线程相关的业务逻辑放在run()方法,但是run()方法没有参数也没有返回值的。 主要三种: 构造函数传参(上边用过) 成员变量传参(setName) 回调函数传参

实现的方式主要有三种

在这里插入图片描述

主线程等待法

自己实现循环等待逻辑,需要循环等待的多,代码变得臃肿 循环多久不确定,无法精准控制

CycleWait

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-27 20:49
 */
public class CycleWait implements Runnable{

    private String value;

    @Override
    public void run() {
        try {
            Thread.sleep(3000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value = "we have data now";
    }


    public static void main(String[] args) throws InterruptedException {
        CycleWait cw = new CycleWait();
        Thread t = new Thread(cw);
        t.start();

        // 主线程等待法
        while (cw.value == null) {
            Thread.sleep(100);
        }

        // 未加等待法 null, 加了等待法 we have data now
        System.out.println(cw.value);

    }
}

Thread类join()方法阻塞当前线程,等待当前子线程执行完毕

比主线程等待法实现更简单 控制更精准 t.join();

实现粒度低。 【无法同时多个线程的run()实现】

CycleWait

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-27 20:49
 */
public class CycleWait implements Runnable{

    private String value;

    @Override
    public void run() {
        try {
            Thread.sleep(3000);

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value = "we have data now";
    }


    public static void main(String[] args) throws InterruptedException {
        CycleWait cw = new CycleWait();
        Thread t = new Thread(cw);
        t.start();

//        // 主线程等待法
//        while (cw.value == null) {
//            Thread.sleep(100);
//        }

        // join法阻塞当前线程执行后执行 we have data now
        t.join();

        // 未加等待法 null, 加了等待法 we have data now
        System.out.println(cw.value);

    }
}

通过Callable接口实现:通过FutureTask Or 线程池获取

线程池实现提交多个Callable的类,去让线程池并发的处理结果。 统一对Callable的类进行统一的管理

MyCallable

package thread;

import java.util.concurrent.Callable;

/**
 * @Author bennyrhys
 * @Date 2020-03-27 21:26
 */
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        String value = "test";
        System.out.println("Ready to work");
        Thread.sleep(5000);
        System.out.println("task done");
        return value;
    }
}

MyCallableMain-FutrueTask接收

package thread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
FutrueTask接收
 * @Author bennyrhys
 * @Date 2020-03-27 21:34
 */
public class MyCallableMain {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<>(new MyCallable());
        new Thread(task).start();
        if (!task.isDone()) {
            System.out.println("task has not finished, please wait");
        }
        System.out.println("task return" + task.get());
    }
}

task has not finished, please wait Ready to work(五秒后) task done task returntest

ThreadPoolDemo-线程池接收

package thread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 线程池接收
 * @Author bennyrhys
 * @Date 2020-03-27 21:56
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        Future<String> future = newCachedThreadPool.submit(new MyCallable());

        if (!future.isDone()) {
            System.out.println("task has not finished, please wait!");
        }

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            newCachedThreadPool.shutdown();
        }
    }
}

task has not finished, please wait! Ready to work task done test

源码理解

接收的FutrueTask->Runnable FutrueTask实现的方法

线程池

线程的状态

官方说法及源码

六个状态

新建:未start() 运行:调用了start(),Ready获得cpu的使用时间后->Running 无限期等待:需要被显示的唤醒,nodef 结束:线程一旦终止不能复生。终止的再调start()会抛异常

Sleep和Wait的区别

差别

源码

wait()唤醒阻塞, 即使不传参,调用的也是带参数的,无限期等待

代码-通过等待时间唤醒wait()

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-28 16:05
 * 先锁定的状态
 * Thread A is waiting to get lock
 * Thread A get lock
 * Thread B is waiting to get lock
 * Thread A do wait method
 * Thread B get lock
 * Thread B is sleeping 10ms
 * Thread B is done
 * Thread A is done
 *
 * 翻转情况-a不释放锁,一直到执行完毕
 * Thread A is waiting to get lock
 * Thread A get lock
 * Thread B is waiting to get lock
 * Thread A do wait method
 * Thread A is done
 * Thread B get lock
 * Thread B is sleeping 10ms
 * Thread B is done
 */

public class WaitSleepDemo {
    public static void main(String[] args) {
        // wait()必须由Object创建
        final Object lock = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread A is waiting to get lock");
                synchronized (lock) {
                    try {
                        System.out.println("Thread A get lock");
                        Thread.sleep(20);
                        System.out.println("Thread A do wait method");
                        Thread.sleep(1000);
//                        lock.wait(1000);
                        System.out.println("Thread A is done");
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        // 强制上方线程先执行
        try {
            Thread.sleep(10);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread B is waiting to get lock");
                synchronized (lock) {
                    try {
                        System.out.println("Thread B get lock");
                        System.out.println("Thread B is sleeping 10ms");
                        lock.wait(10);
//                        Thread.sleep(10);
                        System.out.println("Thread B is done");
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}

代码-通过notify和notifyAll唤醒wait()

package thread;

/**
 * @Author bennyrhys
 * @Date 2020-03-28 16:05
 * 先锁定的状态
 * Thread A is waiting to get lock
 * Thread A get lock
 * Thread B is waiting to get lock
 * Thread A do wait method
 * Thread B get lock
 * Thread B is sleeping 10ms
 * Thread B is done
 * Thread A is done
 *
 * 翻转情况-a不释放锁,一直到执行完毕
 * Thread A is waiting to get lock
 * Thread A get lock
 * Thread B is waiting to get lock
 * Thread A do wait method
 * Thread A is done
 * Thread B get lock
 * Thread B is sleeping 10ms
 * Thread B is done
 */

public class WaitSleepDemo {
    public static void main(String[] args) {
        // wait()必须由Object创建
        final Object lock = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread A is waiting to get lock");
                synchronized (lock) {
                    try {
                        System.out.println("Thread A get lock");
                        Thread.sleep(20);
                        System.out.println("Thread A do wait method");
//                        Thread.sleep(1000);
                        lock.wait(); // 进入无限的等待当中

                        System.out.println("Thread A is done");
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        // 强制上方线程先执行
        try {
            Thread.sleep(10);
        }catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread B is waiting to get lock");
                synchronized (lock) {
                    try {
                        System.out.println("Thread B get lock");
                        System.out.println("Thread B is sleeping 10ms");
//                        lock.wait(10);
                        Thread.sleep(10);
                        System.out.println("Thread B is done");
                        lock.notifyAll(); // 用其他线程 唤醒沉睡的线程
                    }catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}

notify和notifyall的区别

概念-等待池-锁池

多线程抢占锁,如果某对象没有竞争到锁,只会留在锁池中,不会在等待池中

区别

代码-区分唤醒一个,全部唤醒【对锁造成的影响】

import java.util.logging.Level;
import java.util.logging.Logger;

public class NotificationDemo {
    private volatile boolean go = false;

    public static void main(String args[]) throws InterruptedException {
        final NotificationDemo test = new NotificationDemo();

        Runnable waitTask = new Runnable(){

            @Override
            public void run(){
                try {
                    test.shouldGo();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " finished Execution");
            }
        };

        Runnable notifyTask = new Runnable(){

            @Override
            public void run(){
                test.go();
                System.out.println(Thread.currentThread().getName() + " finished Execution");
            }
        };

        Thread t1 = new Thread(waitTask, "WT1"); //will wait
        Thread t2 = new Thread(waitTask, "WT2"); //will wait
        Thread t3 = new Thread(waitTask, "WT3"); //will wait
        Thread t4 = new Thread(notifyTask,"NT1"); //will notify

        //starting all waiting thread
        t1.start();
        t2.start();
        t3.start();

        //pause to ensure all waiting thread started successfully
        Thread.sleep(200);

        //starting notifying thread
        t4.start();

    }
    /*
     * wait and notify can only be called from synchronized method or bock
     */
    private synchronized void shouldGo() throws InterruptedException {
        while(go != true){
            System.out.println(Thread.currentThread()
                    + " is going to wait on this object");
            wait(); //release lock and reacquires on wakeup
            System.out.println(Thread.currentThread() + " is woken up");
        }
        go = false; //resetting condition
    }

    /*
     * both shouldGo() and go() are locked on current object referenced by "this" keyword
     */
    private synchronized void go() {
        while (go == false){
            System.out.println(Thread.currentThread()
                    + " is going to notify all or one thread waiting on this object");

            go = true; //making condition true for waiting thread
            //notify(); // only one out of three waiting thread WT1, WT2,WT3 will woke up
            notifyAll(); // all waiting thread  WT1, WT2,WT3 will woke up
        }

    }
}

yield函数

概念

代码-体会暗示,随机

public class YieldDemo {
    public static void main(String[] args) {
        Runnable yieldTask = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 10; i++) {
                    System.out.println(Thread.currentThread().getName() + i);
                    if (i == 5) {
                        Thread.yield();
                    }
                }
            }
        };
        Thread t1 = new Thread(yieldTask, "A");
        Thread t2 = new Thread(yieldTask, "B");
        t1.start();
        t2.start();
    }
}

到5切换线程,接受暗示

到5不切换线程,忽略暗示

代码-yield对锁的影响-不会放弃当前锁

如何中断线程

废弃

stop()一个线程,调用另一个线程停止。 这种不妥,未知另一个状态,导致线程无法清理完成释,放锁,数据异常。

interrupt() 暗示通知线程该中断

代码-对Interrupt的验证

public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Runnable interruptTask = new Runnable() {
            @Override
            public void run() {
                int i = 0;
                try {
                    //在正常运行任务时,经常检查本线程的中断标志位,如果被设置了中断标志就自行停止线程
                    while (!Thread.currentThread().isInterrupted()) {
                        Thread.sleep(100); // 休眠100ms
                        i++;
                        System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") loop " + i);
                    }
                } catch (InterruptedException e) {
                    //在调用阻塞方法时正确处理InterruptedException异常。(例如,catch异常后就结束线程。)
                    System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().getState() + ") catch InterruptedException.");
                }
            }
        };
        Thread t1 = new Thread(interruptTask, "t1");
        System.out.println(t1.getName() +" ("+t1.getState()+") is new.");

        t1.start();                      // 启动“线程t1”
        System.out.println(t1.getName() +" ("+t1.getState()+") is started.");

        // 主线程休眠300ms,然后主线程给t1发“中断”指令。
        Thread.sleep(300);
        t1.interrupt();
        System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted.");

        // 主线程休眠300ms,然后查看t1的状态。
        Thread.sleep(300);
        System.out.println(t1.getName() +" ("+t1.getState()+") is interrupted now.");
    }
}

前述方法及线程状态总结

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!
本文分享自作者个人站点/博客:https://blog.csdn.net/weixin_43469680复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • Java多线程与并发

    答:进程是资源分配的最小单位,线程是CPU调度的最小单位。   1)、进程是资源分配的基本单位,所有与进行相关的资源,都被记录在进程控制块PCB中,以表示该进程...

    别先生
  • Java多线程与并发-原理

    MonitorJava娘胎创建的锁 管程 或 监视器锁(描述为 同步工具,或同步机制,通常被描述为同步对象)

    瑞新
  • Java并发编程与高并发之多线程

    1、线程池,初始化好线程池的实例以后,将要执行的任务丢到线程池里面,等待任务的调度执行。

    别先生
  • Java并发指南1:并发基础与Java多线程

    本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看

    Java技术江湖
  • JAVA多线程与并发学习总结

    使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行;当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存...

    烂猪皮
  • Java多线程与并发笔记

    synchronized主要是用于解决线程安全问题的,而线程安全问题的主要诱因有如下两点:

    端碗吹水
  • Java并发多线程

    并发知识不管在学习、面试还是工作过程中都非常非常重要,看完本文,相信绝对能助你一臂之力。

    一个会写诗的程序员
  • Java高并发与多线程网络编程

    当JVM启动时,会创建一个非守护线程 main,作为整个程序的入口,以及多个与系统相关的守护线程。

    devi
  • 多线程与并发

    用户6182664
  • Java多线程与并发面试题

    线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速。比...

    Kevin_Zhang
  • Java实现多线程并发

    流柯
  • Java 并发编程:多线程并发内存模型

    多任务处理在现代计算机操作系统中几乎已是一项必备的功能了。在许多情况下,让计算机同时去做几件事情,不仅是因为计算机的运算能力强大了,还有一个很重要的原因是计算机...

    码农架构
  • Java 并发编程:多线程如何实现阻塞与唤醒

    线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢...

    码农架构
  • Java并发编程:多线程如何实现阻塞与唤醒

    线程的阻塞和唤醒在多线程并发过程中是一个关键点,当线程数量达到很大的数量级时,并发可能带来很多隐蔽的问题。如何正确暂停一个线程,暂停后又如何在一个要求的时间点恢...

    码农架构
  • Java面试考点3之并发与多线程

    线程是 JVM 执行任务的最小单元,理解线程的状态转换是理解后续多线程问题的基础。在 JVM 运行中,线程一共有 NEW、RUNNABLE、BLOCKED、WA...

    马拉松程序员
  • Java并发性和多线程

    例如一个应用程序需要从本地文件系统中读取和处理文件的情景. 比方说, 从磁盘读取一个文件需要5s, 处理一个文件需要2s. 那么处理两个文件就需要:

    烟草的香味
  • Java多线程并发最佳实践

    编写并发代码是比较难,尽管Java语言提供了许多同步和并发支持,但是最终写出没有Bug的Java并发代码还是需要依靠个人的勤奋与专业知识。Java多线程并发最佳...

    lyb-geek
  • JAVA高并发处理------多线程

    线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的。

    HUC思梦

扫码关注腾讯云开发者

领取腾讯云代金券