线程

作者: 面向星辰大海的程序员 | 来源:发表于2020-04-11 21:38 被阅读0次

java线程多线程

public class JavaStudy { 
public static void main(String[] args) { 
System.out.println("java线程学习");  
//虚拟机线程管理的接口 
ThreadMXBean threadMXBean =ManagementFactory.getThreadMXBean();     
//取得线程管理信息       
ThreadInfo[] threadInfo = threadMXBean.dumpAllThreads(false, false);  
//Java天生多线程  
for (ThreadInfo info : threadInfo) {    
System.out.println("[" + info.getThreadId() + "]" + info.getThreadName()); 
} 
  System.out.println("");
        System.out.println("beautiful line--------------" + Thread.currentThread());
        System.out.println("");

        UserThread userThread = new UserThread();
        userThread.start();

//无返回值的任务   
     ImplRunnable implRunnable = new ImplRunnable();
        new Thread(implRunnable).start();

//有返回值的任务
        ImplCallable implCallable = new ImplCallable();
        FutureTask<String> futureTask = new FutureTask<>(implCallable);
        new Thread(futureTask).start();

        try {
            System.out.println("return==" + futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

}
}


1.png

如何新建线程

 //How create Thread?

    //extends Thread
    public static class UserThread extends Thread {

        @Override
        public void run() {
            super.run();
            System.out.println(Thread.currentThread() + "I am extends Thread");
        }
    }

    //implements Runnable interface
    public static class ImplRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread() + "I am implements Runnable");
        }
    }

    /*implements Callable  ,allow return value**/
    public static class ImplCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println(Thread.currentThread() + "I am implements Callable");
            return "I am ImplCallable return value";
        }
    }

总结:java天生是一个多线层的语言,新建线程有三中方式
1.new UserThread().start();
2.new Thread(new Runnable()).start();
3.new Thread(new FutureTask<>(new Callable())).start();

Runnable和Callable是对任务的抽象
对线程的抽象只有Thread
调用start()方法才是真的启动了一个线程

终止线程:
强制中断的后果:

协作式:
interrupted()叫停线程
isInterrupted()判断线程是否被叫停
Thread.isInterrupted() 调用之后又会把标志位改为false

UserThread.interrupted();
 public static class UserThread extends Thread {

        @Override
        public void run() {
            super.run();
            System.out.println( "I am extends Thread"+isInterrupted());这会打印false
            while (!isInterrupted()) {//被叫停就中断循环
                System.out.println( "I am extends Thread  is Running");
            }
            System.out.println( "I am extends Thread  is Running" + isInterrupted());//这会打印true
        }
    }

join():哪个线程调用就哪个线程优先执行
yield():让出执行权,让出后系统可能又会选自己执行
start():线程准备好了,但是不一定马上执行,等系统调度
sleep():线程进入阻塞状态,sleep()时间到了或者interrupt()中断了就会进入就绪状态,属于线程的休眠,不会释放锁
wait():线程进入阻塞状态,notify()或者notifyAll()进入就绪状态,不满足执行条件,等通知,也可以设定一定时间后继续执行,阻塞其间释放锁

线程间的共享和协作:
synchronized 内置锁,同一时间只能有一个线程访问锁
用法 :
锁方法

 public synchronized void countAdd() {//锁 this  就是当前对象
            count++;
        }

锁对象

 private Object object = new Object();
        public void countAdd() {this
            synchronized (object) {//锁 自己new的对象,    也可这么写 synchronized (this)
                count++;
            }
        }

这两种方法没太大区别都叫对象锁

提出疑问
假如当前对象有两个属性,其中一个加锁访问,另一个不加锁,起两个线程访问对应的两个属性,即线程1访问属性1,2访问2,访问加锁的属性的同时,不加锁的属性能被另一个线程访问么?
锁的是代码块,就是被synchronized包住的代码块或被synchronized修饰的方法
不被锁的其他代码块能被其他线程访问,不受影响
使用不同的对象锁不同的代码块,互不影响
使用相同的对象锁不同的代码块,哪个线程先得锁哪个线程先得访问

类锁
静态方法 static 后面加synchronized 锁.class对象,其实就是对象锁

总结:看似锁对象其实是作用在代码块,对象就像是一把锁的唯一标识

什么是线程间的协作?
条件不符时阻塞等待唤醒,修改条件唤醒阻塞线程,
wait() notify() notifyAll() 如何理解和使用?

等待通知的标准范式
等待方:
1.获取对象的锁
2.检查条件,条件不满足时 wait()
3.条件满足时,执行业务代码
syn(对象){
whilw(条件不满足){
对象.wait()//调通wait()锁就会被释放
}
//执行业务代码
}
通知方:
1.获取对象的锁
2.修改条件
3.通知等待方
syn(对象){
//执行业务代码,修改条件
对象.notifyAll()//并不会释放
}//代码块执行完之后才会释放

 public class CountBean {
        public static final int MaxCount = 5;
        private int i = 0;

        public synchronized void Iadd() {//线程1调用这
            i++;
            System.out.println(Thread.currentThread().getName() + "  i=" + i);
            notifyAll();
        }

        public synchronized int getI() throws InterruptedException {//线程2调用这
            while (i < MaxCount) {
                wait();//阻塞 等其他线程占有时调用notify或notifyAll方法,并再次获得锁后,条件一直符合,就一直循环阻塞
            }
            return i;
        }
    }

ThreadLocal:线程隔离

 static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {//静态修饰保证全虚拟机只有一份
        @Override
        protected Integer initialValue() {//初始化值
            return 0;
        }
    };

    private Runnable runnable = new Runnable() {//假如三个线程都跑这个任务
        @Override
        public void run() {
            for (int k = 0; k <3 ; k++) {//看起来是使用了一个threadLocal对象,但是每个线程之间没有影响
                int i = threadLocal.get();
                i++;
                threadLocal.set(i);
                System.out.println(Thread.currentThread().getName() + "   i=" + threadLocal.get());//正常的打印出三个线程的累加
            }

        }
    };
2.png

显示锁:Lock
synchronized 获取锁没有中断,就是没拿到锁我就等着,没有尝试获取锁
Lock是个接口,jdk有几个实现类:

3.jpg

使用范式

  private Lock lock = new ReentrantLock();
    public void main() {
        lock.lock();
        try {
            //业务代码,有可能发生异常
        } finally {//不管业务代码怎么样,一定能释放锁
            lock.unlock();
        }
    }

ReentrantLock 可重入锁
什么是可重入锁:线程拿到锁,没释放锁,再次访问同一个锁,还能拿到这个锁,拿多少次就累加记录,这就是可重入锁,synchronized也是可重入锁,在递归调用有锁的方法时防止自己锁死自己。

锁的公平非公平:
公平:先取锁的线程一定先拿到锁
非公平:先取锁的线程不一定先拿到(性能更好 synchronized是非公平,ReentrantLock 默认非公平 构造传true就是公平锁)

为什么非公平更好?
线程挂起唤醒,上下文切换大约需要20000个时间周期,挂起一次20000,唤醒一次20000,
如果是公平锁就得等前面先挂起的线程先拿锁执行,如果刚好可以拿锁不用挂起再唤醒就可以省去40000个时间周期,整体来说非公平锁性能优于公平锁,大概的说。

排他锁:有且只有一个线程能拿到的锁(synchronized)

ReentrantReadWriteLock 读写锁
读:允许有多个线程拿锁读取文件数据,排斥写线程,防止数据不一致
写:只允许一个线程写数据,排斥其他线程,防止数据不一致

为什么会有读写锁?
在生活中读比写的比例大约在10:1左右,读写分离,资源分配合理

 public class Merchandise {
        private final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
        private final Lock getLock = reentrantReadWriteLock.readLock();//读锁    10个线程访问
        private final Lock setLock = reentrantReadWriteLock.writeLock();//写锁      1个线程访问

        public  void setPrice() throws InterruptedException {

            setLock.lock();
            try {
                Thread.sleep(5);//模拟写花的时间
            } finally {
                setLock.unlock();
            }
        }

        public  void getPrice() throws InterruptedException {
            getLock.lock();
            try {
                Thread.sleep(5);//模拟读花的时间
            } finally {
                getLock.unlock();
            }
        }
    }

Condition:

 public class Express {
        public static final String ST_shanghai = "shanghai";
        public static final String ST_beijing = "beijing";
        private String currentStation = ST_shanghai;
        private int distance = 0;
        private Lock lock = new ReentrantLock();//一把锁多个开关
        private Condition stationCondition = lock.newCondition();//开关1
        private Condition distanceCondition = lock.newCondition();//开关2

        public void changeStation(String station) {
            lock.lock();
            try {
                currentStation = station;//条件改变
                stationCondition.signal();//开关1发出一个通知
            } finally {
                lock.unlock();
            }
        }

        public void changeDistance(int distance) {
            lock.lock();
            try {
                this.distance = distance;//条件改变
                distanceCondition.signalAll();//开关2发出一个通知
              //  distanceCondition.signal();//开关2发出一个通知
            } finally {
                lock.unlock();
            }
        }

        public void waitStation() {
            lock.lock();
            try {
                while (currentStation.equals(ST_shanghai)) {
                    try {
                        System.out.println(Thread.currentThread().getName() + "  waitStation");
                        stationCondition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "  Station is Change");
            } finally {
                lock.unlock();
            }
        }

        public void waitDistance() {
            lock.lock();
            try {
                while (distance < 100) {
                    try {
                        System.out.println(Thread.currentThread().getName() + "  waitDistance");
                        distanceCondition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "   Distance is Change");
            } finally {
                lock.unlock();
            }

        }
    }

线程池的优点 :
1.复用,节约资源 2.响应速度块(省掉创建的时间)3.提高线程的可管理

简单的线程池:
public class ThreadPool {
    private int coreThreadCount = 5;
    private int defaultTaskCount = 100;
    private WorkThread[] workThreads;
    private final BlockingQueue<Runnable> taskQueue;

    public ThreadPool() {
        taskQueue = new ArrayBlockingQueue<>(defaultTaskCount);
        workThreads = new WorkThread[coreThreadCount];
        for (int i = 0; i < coreThreadCount; i++) {
            workThreads[i] = new WorkThread();
            workThreads[i].start();
        }
        System.out.println("cpuCoreCount=" + Runtime.getRuntime().availableProcessors());
    }

    public void execute(Runnable task) {
        try {
            taskQueue.put(task);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void destroy() {
        for (int i = 0; i < coreThreadCount; i++) {
            workThreads[i].interrupt();
            workThreads[i] = null;

        }
        taskQueue.clear();
    }

    public class WorkThread extends Thread {
        @Override
        public void run() {
            super.run();
            Runnable runnable = null;

            try {
                while (!isInterrupted()) {
                    runnable = taskQueue.take();
                    if (runnable != null) {
                        runnable.run();
                    }
                    runnable = null;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        }
    }
}
   ThreadPool threadPool = new ThreadPool();

        for (int i = 0; i < 10; i++) {
            threadPool.execute(new ImplRunnable("Task" + i));
        }
    }

    public static class ImplRunnable implements Runnable {
        private String taskName;

        public ImplRunnable(String taskName) {
            this.taskName = taskName;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("complete:" + taskName);
        }
    }

jdk线程池:

jdkThreadPool.png
corePoolSize: 核心线程数,线程池保留的最小线程数
maximumPoolSize: 最大线程数,当任务队列装不下之后就开始创建新的线程
keepAliveTime: 空闲线程存活时间,保留的线程数等于核心线程数
unit: 时间单位,对应keepAliveTime
workQueue: 任务缓冲阻塞队列,核心线程都在工作时候添加到队列
threadFactory: 搞线程名的
handler: 溢出策略(饱和策略,拒绝策略),当最大线程数也满了之后开始响应策略

jdk提供的几种策略:

reject.png
AbortPolicy:直接抛出异常(jdk默认)
CallerRunsPolicy:哪个线程提交的任务它自己执行
DiscardPolicy:直接丢到要放进来的任务
DiscardOldestPolicy:丢弃阻塞队列最先进去的任务

自定义策略:自己实现RejectedExecutionHandler

BlockingQueue:

blockingqueue.png
add remove
offer poll
put take 阻塞

常用的BlockingQueue:
ArrayBlockingQueue:
LinkedBlockingQueue:

合理使用分配线程:
Cpu密集型:不要超过Cpu同时运行的线程数 Runtime.getRuntime().availableProcessors()取得线程数
IO密集型 :2*Cpu同时运行的线程数
混合型:拆分成以上两个

AsyncTask:

volatile 保证可见性 不保证原子性

相关文章

  • Android

    线程间通信 主线程和工作线程主线程和工作线程 工作线程与工作线程工作线程与工作线程 为什么主线程Looper.lo...

  • 三、操作系统之线程

    前言 什么是线程 引入线程的原因 线程的概念 线程和进程的关系 线程结构 线程有点 多线程模型 用户线程和内核线程...

  • Thread

    队列 线程锁 多线程,线程池 队列 多线程爬虫示例 多线程 自定义线程 线程池

  • 总结多线程与设计模式+synchronized+性能+高吞吐+死

    Java线程 Java语言的线程 何谓线程 线程启动 线程的暂时停止 线程的共享互斥 线程的协调 线程的状态转移 ...

  • 多线程编程

    摘要 线程概念,线程与进程的区别与联系学会线程控制,线程创建,线程终止,线程等待了解线程分离与线程安全学会线程同步...

  • java线程池

    线程VS线程池 普通线程使用 创建线程池 执行任务 执行完毕,释放线程对象 线程池 创建线程池 拿线程池线程去执行...

  • java并发之守护线程

    java中有两种线程,用户线程和守护线程用户线程:主线程停止时,用户线程不会停止守护线程:主线程停止时,守护线程也...

  • Java线程池的使用

    线程类型: 固定线程 cached线程 定时线程 固定线程池使用 cache线程池使用 定时调度线程池使用

  • 线程基础知识

    线程学习 线程的基础知识 线程是什么? 线程和进程的关系 线程的6个状态 线程优先级 主线程、多线程、后台线程的概...

  • 多线程介绍

    一、进程与线程 进程介绍 线程介绍 线程的串行 二、多线程 多线程介绍 多线程原理 多线程的优缺点 多线程优点: ...

网友评论

      本文标题:线程

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