前言
1:发挥多核CPU的优势(充分利用cpu资源)
如果是单线程的程序,那么在双核CPU上就浪费了50%,在4核CPU上就浪费了75%。单核CPU上所谓的”多线程”那是假的多线程,同一时间处理器只会处理一段逻辑,只不过线程之间切换得比较快,看着像多个线程”同时”运行罢了。多核CPU上的多线程才是真正的多线程,它能让你的多段逻辑同时工作,多线程,可以真正发挥出多核CPU的优势来,达到充分利用CPU的目的。多线程完成cpu内核的快速切换,提高CPU的利用率
2:防止阻塞
假如单线程执行的时候在返回数据的时候迟迟没有返回,然后此时线程就会出现阻塞 要是多线程的话,那么要是有一个阻塞了也不会影响其他线程的执行单核CPU上运行多线程导致线程上下文的切换,而降低程序整体的效率
3:便于建模
就是一个大任务,拆分成多个小任务,此时就十分简单了
4:提高程序执行效率
也就是上文中的利用多个线程用多核cpu的情况,可以在多核cpu的都在进行工作没有休息,就防止cup在休息然后不工作的情况
进程和线程:
进程:一个程序运行的时候叫做进程
线程:一个进程启动会有多个线程 最少有两个线程(gc 和 主)
//main 方法执行: 需要一个线程,该线程由jvm创建(主线程)
//后台线程,垃圾回收线程(g2)
线程之间可以数据共享
并发:在同一时间一起访问线程(有可能出现异常)
并行:在同一时间段上一起访问线程 必须多核 然后同时运行
线程存在的意义:其实是为了提高进程的效率 就是可以在同一时间开启多个线程
线程的创建和启动
两种方式创建线程
1:继承于Thread
-自定义继承Thread
-复写run方法
-创建自定义类对象
-自定义对象调用start方法
//继承Thread类来自定义一个线程类
class MyThread extends Thread{//分配任务 来自于父类的方法public void run(){//方法写在这里 线程执行体System.out.println("听音乐");}public static void main(String[] args){MyThread myThread = new MyThread();myThread.start(); //线程启动 将当前线程交给cup来调度//当抢到cpu资源时,执行其中run方法System.out.println("玩游戏");}
}//此时代码主线程先开启 开启执行调用线程 此时线程数(3)
//我们现在有 主线程 和cpu来决定谁抢到cpu资源 然后自定义和
//主线程就开始竞争资源了 谁抢到就是谁的了
注意:只有当线程有竞争关系的时候才能体现出来 且不会因为主线程的结束而结束当前线程 只有在所有线程结束之后才会结束当前线程
2:实现Runable
-自定义实现Runnable接口
-覆写run方法
-创建自定义类对象
-把自定义类的对象作为Thread对象的参数创建
(本质就是用Thread的一个构造器来创建一个启动线程的方法)
-使用Thread类的对象调用start方法
创建Thread的时候传入一个String的时候 其实就是为线程赋予名字
//编写线程中需要执行的方法 public MyRunnable implement Runnable{public void run(){//线程体 写一个线程中要执行的代码for(int i = 0;i<10;i++){System.out.println("玩游戏);}}
}public MyRunnableDemo{public static void main(String[] arge){//创建对象MyRunnable m = new Myrunnable();//传入m代码是 Thread执行的任务为m内run方法Thread t = new Thread(m);t.start();for(int i = 0;i<10;i++){System.out.println("听音乐);}}
}
线程声明周期的状态
线程的开始 是在new的时候就开始了
1:可运行 排队 和执行状态
2:等待 等待另一个线程来唤醒他
3:计时等待 万一没人唤醒自己定时醒
4:阻塞状态 遇到特俗情况(如IO) 让出自己的cpu资源
5:终止 当线程执行完毕就结束了 也可以强停
常用方法
1:join 让当前线程执行完毕 之后再执行其他的线程
使其他资源让出自己的资源
(同步 a完事之后 再执行b)
(异步 a和b交替执行 //平时的执行方法)
2:sleep(long milllis) 计时等待 一般模拟网络延迟
3:线程优先级 可以提供他和其他线程抢cpu执行的机会
但是不是绝对高 只是和cpu调用有关 1-10 默认是5
Tread对象设置优先级setPriority(int x)和 获取getpriority()获取优先级
4:后台线程 又名守护线程 守护其他的普通线程
所有的前台线程此时后台延迟自程死亡
setDaemon() 将当前线程设置为后台线程(不能再start后)
用Thread和Runnable创建线程区别
一:使用Thread方法创建线程
常用语法区别
1:super.getName(); //获取当前线程名字
2:设置获取线程名字区别
(1):线程名.setName("");
(2):我们可以再构造器中设置名字
子类中调用父类构造器 再子类中提供一个构造器 然后调用父类构造器 此时就可以再测试类创建对象的时候直接初始化名字没有必要再设置了 这种方式更加简单;每个对象都会有一个成员变量值都是相等的 每次改变的都是自己的所以不能共享 此时我们把成员变量设置为静态的成员 此时无论几个对象都是访问一个字段对象
二:使用Runnable方法,可以实现资源共享在启动的时候需要多执行一部
常用语法区别
1:Thread.currentThread().getName(); //获取当前线程名字
2:设置获取线程的名字区别
(1)通过Thread(Runnable run,String name); 可以传入名字
(2)new Thread(Runnabel run).setName();
实现资源 要不就是资源是大家的一起共有的 在不就是大家只有一个
synchronized同步
当多个线程并发访问同一个资源的时候,可能出现线程不安全的问题
就是一个线程在执行的时候可能被其他线程抢走此时就出现错误了然后就
此时引入Synchronized哪一个线程拿到此锁的时候就会在里面执行并且把其他线程隔绝在外面
同步方法 //不需要我们自己指定锁对象
//锁对象
对于非static方法,同步锁就是this
对于static方法,同步锁就是当前方法所在类的字解码对象synchronized public void 方法名(){需要同步的方法体 }
注意:当我们使用继承的方法的时候 尽量使用静态的锁方法 如果使用非静态的就会出现错误 因为this只是指向当前对象 然后当有多个对象的时候就会出现对象指向不明的问题
同步代码块 //需要我们自己指定锁对象
//锁对象 保证使用同一个对象作为锁对象即可
实现方式:锁对象直接用this就好 因为只有一个对象
synchronized(同步锁对象插入位置一般为this){ 需要同步的代码块}
继承方式:锁对象就不能用this了 因为不是只有一个对象 此时如何保证同一个对象 1:自定义线程对象.class 同一份字解码对象 2:可以在自定义线程 让一个对象代表三个/更多对象Objetc obj = new Object();
注意:我们保证多个线程共用一个对象才可以 不然还是锁不住,并且要尽量减少同步代码块的作用域.
原子性操作
:在执行这段代码的时候不要让其他人进来 关门操作一个或者几个操作在一个线程执行完毕之后,另一个线程才能开始执行该操作
最后
感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!