多线程

写出来的程序,执行后就是一个进程,一个进程中包含多个线程,比如说main线程、gc线程等

线程的创建

1、继承Thread类、

2、实现Runnable接口

3、实现Callable接口

 

线程开启不一定立即执行,由cpu调度执行

推荐使用实现Runnable接口的方式来创建线程,原因是:

1、java单继承的局限性,所以使用实现接口的方式

2、实现Runnable接口可以实现多个线程操作同一对象

实现Callable接口,实现的是call方法,其他都是run方法

 

 

另一种方式

 

Callable的好处:

1、可以定义返回值

2、可以抛出异常

Callable不常用,了解就可以了,重点还是实现Runnable接口

 

静态代理:

真实对象和代理对象要实现同一接口,代理对象要代理真实对象

Thread类就是静态代理模式,new Thread().start();

好处:代理对象可以做很多真实对象做不了的事情

真实对象专注做自己的事情就好了

 

Lamda表达式

jdk1.8新特性

接口中,成员变量的默认修饰符是public static final

接口中,方法的默认修饰符石public abstract

任何接口,如果只有唯一一个抽象方法,那么他就是一个函数式接口,对于函数式接口,就可以通过lamda表达式来创建该接口的对象

为什么要是用lamda表达式?

  • 避免匿名内部类定义过多

  • 可以让你的代码看起来很简洁

  • 去掉了一堆没有意义的代码,只留下核心的逻辑

 

Love love = (int a,int b) -> {

System.out.println("123123");

}

love = (a,b) -> System.out.println("123123");

  • lamda表达式只能有一行代码的情况下才能简化为一行,如果多行,那么就用代码块包裹

  • 前提是接口为函数式接口,也就是说只有一个抽象方法

  • 多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号

 

线程状态

 

 

线程方法

 

@deprecated 方法上有这种注解的不推荐使用

 

yield

 

 

线程状态

 

thread.getState()

线程处于terminated状态后,不可以再次启动,否则会报错

 

线程优先级

用数字表示,范围从1-10

Thread.MIN_PRIORITY = 1

Thread.MAX_PRIORITY = 10

Thread.NORM_PRIORITY = 5

设置优先级和获取优先级

getPriority() setPriority(int xxx)

优先级设定建议在start()调度前,优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,这都是要看CPU的调度

 

守护(daemon)线程

 

用户线程比如说main线程,守护线程比如说gc线程

thread.setDaemon(true); //设置为守护线程,true为是

 

线程同步

队列+锁实现线程安全,线程安全必定会带来性能的降低,使用锁带来的问题如下:

 

 

 

synchronized会让方法变成同步方法,线程进入会获取到对象的排它锁,其他线程获取不到,就不会进入,这样就保证了安全,synchronized方法只能锁当前对象,也就是this,而synchronized代码块可以锁任意对象,锁的对象就是变化的量,也就是需要增删改的对象

JUC --> java util concurrent

 

死锁

 

lock锁

常用的实现类是ReentrantLock,实现接口Lock

JUC java.util.concurrent 并发领域的包

 

 

线程通信

synchronized只能解决线程同步问题,解决不了线程通信问题

需要使用wait()、wait(long timeout)、notify()、notifyAll()

这几个方法都是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出IllegalMonitorStateException

 

线程池

 

多线程方法总结:

sleep()

属于Thread类,主要的作用是让当前线程停止执行,把cpu让给其他线程执行,不参与sleep期间的cpu调度,但不会释放对象锁和监控的状态,到了指定时间后线程又会自动恢复就绪状态,继续参与cpu的调度

运行状态 -> 阻塞状态 -> 就绪状态 不会释放锁

 

wait()

让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。

让“当前线程”等待(会释放锁),而“当前线程”是指正在cpu上运行的线程

运行状态 -> 阻塞状态 -> 就绪状态 会释放锁

 

notify()

notify()和notifyAll()的作用,则是唤醒当前对象上的等待线程;notify()是唤醒单个线程,而notifyAll()是唤醒所有的线程。

notify选择唤醒其中一个线程。选择是任意性的,由具体实现做出决定.因此设计JAVA程序时,不要依赖于这一点.

 

yield()

它能让当前线程暂停,但不会阻塞该线程,而是由“运行状态”进入到“就绪状态”,从而让 其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是 当前线程又进入到“运行状态”继续运行!

yield()方法不会释放锁。

运行状态 -> 就绪状态

 

join()

当某个程序执行流中调用其他线程的join方法时,调用线程将被阻塞,直到被join的线程执行完毕。

 

interrupt()

interrupt()是Thread类的一个实例方法,用于中断本线程。这个方法被调用时,会立即将线程的中断标志设置为“true”。所以当中断处于“阻塞状态”的线程时,由于处于阻塞状态,中断标记会被设置为“false”,抛出一个 InterruptedException。所以我们在线程的循环外捕获这个异常,就可以退出线程了。

interrupt()并不会中断处于“运行状态”的线程,它会把线程的“中断标记”设置为true,所以我们可以不断通过isInterrupted()来检测中断标记,从而在调用了interrupt()后终止线程,这也是通常我们对interrupt()的用法。

Interrupted()是Thread类的一个静态方法,它返回一个布尔类型指明当前线程是否已经被中断,isInterrupted()是Thread类的实例方法,返回一个布尔类型来判断线程是否已经被中断。它们都能够用于检测对象的“中断标记”。区别是,interrupted()除了返回中断标记之外,它还会清除中断标记(即将中断标记设为false);而isInterrupted()仅仅返回中断标记。

 

interrupt():将调用该方法的对象所表示的线程标记一个停止标记,并不是真的停止该线程。

interrupted():获取当前线程的中断状态,并且会清除线程的状态标记。是一个是静态方法。(测试例子中的当前线程是main线程,调用两次,第二次是false是因为第一次给清除了)

isInterrupted():获取调用该方法的对象所表示的线程,不会清除线程的状态标记。是一个实例方法。

 

isInterrupted() 和 interrupted() 有两点不同:一是不具有清除状态标记功能,因为底层传入 isInterrupted() 方法的参数为 false。二是它判断的线程调用该方法的对象所表示的线程

一段代码

public class Test2{
    public static /*volatile*/ int found = 0;
​
    public static void main(String[] args)  {
        new Thread(new Runnable() {
            public void run() {
                System.out.println("等基友送笔来...");
​
                while (0 == found) {
​
                }
​
                System.out.println("笔来了,开始写字...");
            }
        }, "我线程").start();
​
        new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
​
                System.out.println("基友找到笔了,送过去...");
​
                change();
            }
        }, "基友线程").start();
    }
​
    public static void change() {
        found = 1;
    }
}

把volatile注释掉后,因为线程是有自己内部的工作内存,found值修改后,对第一条线程并不可见,所以陷入死循环

volatile 保证了变量在线程之间的可见性,禁止指令重排

乐观锁悲观锁:

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值