Java从零开始学习——Java多线程(未完结)
Posted kevinsblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java从零开始学习——Java多线程(未完结)相关的知识,希望对你有一定的参考价值。
1.简介
任务:包括用户对计算机操作时的各个动作及所对应的响应事件,如鼠标单击、右击、打开一个对话框、关闭一个文件、启动一个程序等。
程序
进程(Process)则是执行程序的一次执行过程,是一个动态的概念,是系统资源分配的单位,其可以用多个线程。
线程(Thread)是CPU调度和执行的单位,是独立的执行路径。
程序运行时,及时没有自己创建线程,后台也会有多个线程,如主线程,gc线程。
线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能被人为干预的。
对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。
线程会带来额外的开销,如cpu调度实现、并发控制开销。
每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。
很多多线程是模拟出来的,真正的多线程是指由多个cpu,即多核,如服务器。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换得很快,所以就有同事执行的错觉。
1.1 静态代理
真实对象和代理对象都要实现同一个接口
代理对象要代理真实角色
优点:代理对象可以实现真实对象做不了的事件
真实对象可以专注做自己的事情
1 new WeddingCompany(new You()).HappyMary; 2 new Thread(new Runnable()).start();
1.2 Lambda表达式
1 new Thread( ()->sout("Hello,my friend.") ).start();
Functional Interface函数式接口:任何接口,如果只包含为一个抽象方法,name它就是函数式接口。
1 //Lambda表达式简化 2 ILove love = null; 3 love = (int a,int b)->{ 4 System.out.println("i love you"+a); 5 }; 6 ? 7 //简化参数类型 8 love = (a,b)->{ 9 System.out.println("i love you"+a); 10 }; 11 ? 12 //简化括号,多参数不可省略 13 love = a->{ 14 System.out.println("i love you"+a); 15 }; 16 ? 17 //简化花括号,代码有多行时,还是用代码块(花括号包裹) 18 love = a->System.out.println("i love you"+a);
2.线程实现*
2.1 创建线程的方式
-
Thread class*
1 //创建线程类,继承Thread类 2 public class ThreadDemo01 extends Thread 3 { 4 //重写run()方法 5 @Override 6 public void run() 7 { 8 //线程执行体 9 for (int i = 0; i < 20; i++) 10 { 11 System.out.println("我在看代码——"+i); 12 } 13 } 14 ? 15 //main主线程 16 public static void main(String[] args) 17 { 18 //创建接口对象 19 ThreadDemo01 threadDemo01 = new ThreadDemo01(); 20 //调用start方法,开启线程 21 threadDemo01.start(); 22 ? 23 for (int i = 0; i < 20; i++) 24 { 25 System.out.println("我在学习多线程——"+i); 26 } 27 } 28 }
-
Runnable*
1 //创建线程类,实现runnable接口 2 public class ThreadDemo03 implements Runnable 3 { 4 //重写run()方法 5 @Override 6 public void run() 7 { 8 //线程实现体 9 for (int i = 0; i < 20; i++) 10 { 11 System.out.println("我在看代码——"+i); 12 } 13 } 14 ? 15 //main主线程 16 public static void main(String[] args) 17 { 18 //创建runnable接口实现对象 19 ThreadDemo03 t1 = new ThreadDemo03(); 20 ? 21 //创建线程对象,通过线程对象start()方法开启线程,代理 22 new Thread(new ThreadDemo03()).start(); 23 ? 24 for (int i = 0; i < 20; i++) 25 { 26 System.out.println("我在学习多线程——"+i); 27 } 28 } 29 }
-
Callable
1 //创建线程类,实现callble接口,有参数 2 public class CallableDemo01 implements Callable<Boolean> 3 { 4 private String url; 5 private String name; 6 ? 7 public CallableDemo01(String url, String name) 8 { 9 this.url = url; 10 this.name = name; 11 } 12 13 //重写call()方法,有返回值 14 @Override 15 public Boolean call() throws Exception 16 { 17 //线程执行体 18 WedDownloader wedDownloader = new WedDownloader(); 19 wedDownloader.download(url,name); 20 ? 21 System.out.println("下载了名为"+name+"的文件"); 22 return true; 23 } 24 ? 25 //main主线程 26 public static void main(String[] args) throws ExecutionException,InterruptedException 27 { 28 //创建callable接口实现对象 29 CallableDemo01 t1 = new CallableDemo01("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white-d0c9fe2af5.png","百度1.jpg"); 30 CallableDemo01 t2 = new CallableDemo01("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white-d0c9fe2af5.png","百度2.jpg"); 31 CallableDemo01 t3 = new CallableDemo01("https://dss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white-d0c9fe2af5.png","百度3.jpg"); 32 ? 33 //创建执行服务 34 ExecutorService es = Executors.newFixedThreadPool(3); 35 ? 36 //提交执行 37 Future<Boolean> r1 = es.submit(t1); 38 Future<Boolean> r2 = es.submit(t2); 39 Future<Boolean> r3 = es.submit(t3); 40 ? 41 //获取结果 42 boolean rs1 = r1.get(); 43 boolean rs2 = r2.get(); 44 boolean rs3 = r3.get(); 45 ? 46 //关闭服务 47 es.shutdownNow(); 48 } 49 }
3.线程状态
-
创建状态
Thread t = new Thread();
线程对象一旦被创建就进入到新生状态
-
就绪状态
t.start();
调用start()方法后线程立即进入就绪状态,但不以为这立即调度执行
-
阻塞状态
当调用sleep()、wait()或同步锁定时,线程进入阻塞状态,代码不往下执行,直到阻塞事件结束后,重新进入就绪状态,等待cpu调度执行
-
运行状态
进入运行状态的线程,才真正执行线程体的代码块
-
死亡状态
线程中断或结束,一旦进入死亡状态,就不能再次启动
3.1线程方法
-
setPriority(int newPriority) 更改线程优先级
-
static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
-
void join() 等待改线程终止
-
static void yield() 暂停当前正在执行的线程对象,并执行其他线程
-
void interrupt() 中断线程(别用这个方式)
-
boolean is isAlive() 测试线程是否处于活跃状态
3.2 线程停止方法
建议线程自然停止
建议使用标记
不建议使用stop和destroy以及Java不推荐使用的方法
3.3 线程休眠
1 Thread.sleep(1000);
每个对象都有一个锁,sleep不会释放锁
可以模拟网络延时:放大问题的发生性
3.4 线程礼让
让当前正在执行的线程暂停,但不阻塞
线程从运行状态转为就绪状态
让cpu重新调度,所以礼让不一定成功
3.5 Join
Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞(插队)
3.6 线程状态观察
1 public class CheckStateDemo 2 { 3 ? 4 public static void main(String[] args) 5 { 6 Thread thread = new Thread(()-> 7 { 8 for (int i = 0; i < 5; i++) 9 { 10 try 11 { 12 Thread.sleep(1000); 13 } 14 catch (InterruptedException e) 15 { 16 e.printStackTrace(); 17 } 18 } 19 System.out.println("执行体运行结束."); 20 }); 21 ? 22 //观察状态 23 Thread.State state = thread.getState(); 24 System.out.println(state); 25 ? 26 //开启 27 thread.start(); 28 state = thread.getState(); 29 System.out.println(state); 30 ? 31 //只要线程不终止,就一直观察线程状态 32 while(state != Thread.State.TERMINATED) 33 { 34 try 35 { 36 Thread.sleep(100); 37 } 38 catch (InterruptedException e) 39 { 40 e.printStackTrace(); 41 } 42 state = thread.getState(); 43 System.out.println(state); 44 } 45 } 46 }
3.7 线程优先级
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
1 #优先级用数字表示1~10 2 Thread.MIN_PRIORITY = 1; 3 Thread.MAX_PRIORITY = 10; 4 Thread.NORM_PRIORITY = 5; 5 //获取和改变优先级 6 getPriority(); 7 setPriority(int XXX);
3.8 守护线程
线程分为洪湖线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如:后台记录操作日志,监控内存,垃圾回收等待......
1 Thread thread = new Thread(god); 2 thread.setDeamon(true); 3 //用户线程结束后,守护线程也会结束
4.线程同步synchronized*
多个线程操作同一个资源(抢票)
并发:同一个对象被多个线程同时操作
4.1 队列和锁
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时也带来了访问冲突的问题。
当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可再次访问。
4.2 多线程产生的问题
抢票、同时取钱、线程增加数组内容
4.3 同步方法
4.3.1 产生的弊端
-
一个线程持有锁会导致其他所有需要此锁的线程挂起
-
在多线程竞争下,枷锁、释放锁会导致较多的上下文切换和调度延时,引起性能下降问题
-
如果一个优先级高的下城等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能下降问题
4.3.2 锁的实现
实现方法的修饰符+synchronized
同步块 synchronized(obj){}(锁对象)
默认锁的内容是this
锁的对象是变化的(增删改)量
抢票 锁票
取钱 锁钱
增加数组 锁数组
4.4 JUC并发包
1 CopyOnWriteArrayList<String> list= new CopyOnWriteArrayList<String>(); 2 for (int i = 0; i < 10000; i++) 3 { 4 new Thread(()-> 5 { 6 list.add(Thread.currentThread().getName()); 7 }).start(); 8 }
4.5 死锁
多个线程个子战友一些共享的资源,并且相互等待其他线程的资源才能运行,而且倒置两个或者多个线程都在等待对方释放资源,都停止执行的情形。
某一个同步块同时拥有两个以上对象的锁时,就可能会发生。
5.线程通信
6.高级主题
以上是关于Java从零开始学习——Java多线程(未完结)的主要内容,如果未能解决你的问题,请参考以下文章
java多线程高并发学习从零开始——初识volatile关键字
从零开始的Java开发1-6-3 多线程:概念Thread类和Runnable接口创建线程线程的状态和生命周期sleep和join方法优先级同步线程间通信