多线程
Thread
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
- 不建议使用:避免oop单继承局限性
//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程
//总结:注意,线程开启不一定立即执行,由CPU调度执行
public class demo2 extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在想你第"+i);
}
}
public static void main(String[] args) {
//main线程 主线程
//创建一个线程对象
demo2 demo2 = new demo2();
//调用start()方法开启线程
demo2.start();
for (int i = 0; i < 20; i++) {
System.out.println("小葵"+i);
}
}
}
Runnable
- 定义MyRunnable类实现Runnable接口
- 实现run()方法,编写线程和执体
- 创建线程对象,调用start()方法启动线程
- 推荐使用Runnable对象,因为Java单继承的局限性,方便灵活,方便同一个对象被多个线程使用
//创建线程方式2: 实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class demo3 implements Runnable{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++) {
System.out.println("我在想你第"+i);
}
}
public static void main(String[] args) {
//创建runnbale接口的实现类
demo3 demo3 = new demo3();
//创建线程对象,通过线程对象来开启我们的线程,代理
Thread thread = new Thread(demo3);
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("小葵"+i);
}
}
}
Lamda表达式
- 希腊字母表排序第十一位的字母,英文名称为Lamda
- 避免匿名内部类定义过多
- 其实质属于函数式编程的概念
public class demo6 {
public static void main(String[] args) {
ILove love= (int a)->{
System.out.println("i love you "+a);
};
love.love(255);
love=a -> System.out.println("小牛马666"+a);
love.love(123);
/*
1.lambda表达式只能有一行代码的情况下才能简化为一行,如果有多行,那么就用代码块包裹
2.前提是接口为函数式接口
3.多个参数也可以去掉参数类型,要去掉就都去掉,必须加括号,
*/
}
}
interface ILove{
void love(int a);
}
线程休眠
- sleep(时间)指定当前线程阻塞的毫秒数;
- sleep存在异常InterruptedException;
- sleep时间达到线程进入就绪状态;
- sleep可以模拟网络延时,倒计时等。
- 每个对象都有一个锁,sleep不会释放锁;
//模拟倒计时
public class demo7 {
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
//--------------------------
//打印当前系统时间
Date date = new Date();
while (true) {
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
date=new Date();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//--------------------------
}
public static void tenDown() throws InterruptedException {
int num=10;
while (true){
Thread.sleep(1000);
System.out.println(num--);
if (num<=0){
break;
}
}
}
}
线程礼让
- 线程礼让,让当前正在执行的线程暂停,但不阻塞
- 将线程从运行状态转为就绪状态
- 让cpu重新调整,礼让不一定成功!看CPU心情
public class demo8 {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}
线程强制执行join
public class demo8 {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"线程开始执行");
Thread.yield();
System.out.println(Thread.currentThread().getName()+"线程停止执行");
}
}
线程优先级
- Java提供一个线程调度器来控制程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度那个线程来执行。
- 线程的优先级用数字表示,范围从1-10。
- Thread.MIN_PRIORITY=1;
- Thread.MAX_PRIORITY=10;
- Thread.NORM_PRIORITY=5;
- 优先级低只是意为着获取调度的概率低,并不是优先级低就不会被调度了,这都是看CPU的调度
- 使用.getPriority() .setPriority(int xxx) 获取或改变优先级
- 优先级的设定建议在start()调度前
守护线程(daemon)线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录操作日志,监控内存,垃圾回收等待
同步方法
-
由于我们可以通过private关键字来保证数据对象只能被对象访问,使用我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized
public synchronized void method(int args){}
-
synchronized方法控制对象的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行
-
若将一个大的方法申明为synchronized将会影响效率
死锁
- 多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步快同时拥有"两个以上对象的锁"时,就可能会发生"死锁"的问题。
条件
- 互斥条件: 一个资源每次只能被一个进程使用。
- 请求与保持条件: 一个进程因请求资源而阻塞时,对方以获得的资源保持不放。
- 不剥离条件:进程以获得的资源,在未使用完之前,不能强行剥夺。
- 循环等待条件: 若干进程之间形成一种头尾相连的循环等待资源关系。
- 上面列出了死锁的四个必要条件,我们只要想办法破坏其中的任意一个或多个条件就可以避免死锁发生。
线程池
- 背景:经常创建和销毁,使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
- 思路:提前创建好多个多线程,放入线程池中,使用时直接获取,使用完放回线程池中。可以避免频繁创建销毁,实现重复利用。类似生活中的公交通工具。
- 好处:
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理
- corePoolSize:核心池大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程没有任务时保持多长时间会终止