首页 > 编程语言 >java 多线程

java 多线程

时间:2023-01-20 17:57:26浏览次数:36  
标签:同步 java Thread 对象 接口 线程 多线程 方法

process进程 thread线程

三种创建方式

Thread class 继承Thread类

创建线程方式一:继承Thread类,重写run()方法,调用start开启线程(如果是直接调用run方法,实际上是在main线程中进行的)

继承Thread类,首先重写run方法,然后在主程序中创建一个线程对象,调用start方法开启线程

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

理解:在主程序中先实例化Thread的继承类,由于继承了Thread,所以可以直接使用他实例化出来的对象的start方法来开启线程

不建议使用:避免OOP单继承局限性

Runnable接口 实现Runnable接口

创建线程方式2:实现2runnable接口,重写run方法,执行线程需要丢入runnable的实现类(实例化一个Thread对象,用含参构造器),调用start方法

作为Runnable接口的实现类,首先重写run方法,然后再主程序中创建一个runnable接口的实现类,然后创建线程对象,通过线程对象来开启线程,需要用到代理

理解:在主程序中实例化runnable接口的实现类,由于没有继承Thread,所以要实例化Thread。然后运用Thread实例化出来的对象的start方法

推荐使用:避免单继承局限性,方便于同一对象被多个线程使用。同时适合共享资源

TestThread3 testThread3 = new TestThread3();
Thread thread = new Thread(testThread3);
thread.start();
//Thread实例化时要把实现类投入Thread()中
//后两句可以合并为
new Thread(实现类对象名,name).start( )//name类似于对象.name,借此实现同一对象被多个线程使用

Callable接口 实现Callable接口

了解即可

静态代理

真实对象与代理对象都要实现同一个接口

代理对象要代理真实角色,需要将真实角色传入。然后调用代理对象的方法

好处:代理对象可以做很多真实对象做不了的事情,真实对象可以做自己的东西

Lambda表达式

使用目的:避免匿名内部类定义过多,可以让代码更简洁,去掉了没有意义的代码只留下了核心逻辑

函数式接口

任何接口,如果只包含唯一一个抽象方法,那么他就是函数式接口(Runnable就是)

public interface Runnable{
    public abstract void run();
}
//在接口里,void ilike默认包含public abstract

对于函数式接口,我们可以通过lambda表达式来创建该接口的对象

对于一个方法的简化进化史

  1. 定义一个函数式接口,然后用实现类
  2. 为避免在主类外部,采用在主类内部使用静态内部类
  3. 为避免在主方法外部,采用在主方法内部使用局部内部类
  4. 为避免命名类,采用匿名内部类(没有类的名称,必须借助接口或者父类实现,最好要加分号)
  5. 由于只有一个方法,为避免多余的无意义代码,采用lambda表达式
like = ()->{
            System.out.println("I like lambda5");
        };
        like.Lambda();

lambda表达式简化

lambda表达式只能有一行代码时才能简化,不然要用代码块包裹

  1. 可以去掉参数类型(多个也可以去掉,要去掉就都去掉)
  2. 可以去掉括号,只能是只有一个参数时才可以
  3. 可以去掉花括号,
ILove love=(int a)-> {
                System.out.println("i love you"+a);
            };
//在前面ILove love = null;就可以省去ILove
love=(a)-> {
            System.out.println("i love you"+a);
        };
      
love=(a)-> System.out.println("i love you"+a);
 

线程的五大状态

创建状态:线程对象的创建 new

就绪状态:当调用start()方法,线程进入就绪状态,但是不会立刻被调度执行

阻塞状态:当调用sleep,wait或同步锁定时,进入阻塞状态

运行状态:运行时,线程才真正执行线程体的代码块

死亡状态:线程中断或者结束,一旦进入死亡状态就不能再次启动

线程方法

  • setName设置线程名称,使之与参数name相同
  • getName返回该线程的名称
  • start使线程开始执行
  • run,只是一个方法,并不能建立新的线程
  • setPriority(int newPriority) 更改线程的优先级
  • getPriority获取线程的优先级
  • static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
  • void interrupt( ) 中断线程,别用这个方法

void join( ) 等待该线程终止

static void yield( )暂停当前正在执行的线程对象,并执行其他线程

boolean isAlive( ) 测试线程受处于活动状态

停止线程

  • 不推荐使用JDK提供的stop( ),destroy( )方法
  • 推荐线程自己停止下来
  • 建议使用一个标志位进行终止变量,当flag=false,则终止线程运行

线程休眠_sleep

  • sleep(时间)指定当前线程阻塞的毫秒数
  • sleep存在异常InterruptedException
  • sleep时间达到后线程进入就绪状态
  • sleep可以模拟网络延迟,倒计时
  • 每个对象都有一个锁,sleep不会释放锁

模拟网络延迟可以放大问题的发生性

线程礼让_yield

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 让线程从运行状态转为就绪状态
  • 让CPU重新调度,礼让不一定成功,要看CPU

线程强制执行_join

  • join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
  • 可以想象为插队

运行Thread对象vip方法vip.join( )的是被插队的一方,先让vip对象线程执行结束

观察线程状态

get.State( )获取当前状态

state!=Thread.State.TERMINATED 判断变量state是不是TERMINATED

线程优先级

优先级范围是1-10 数字越大,优先级越高

优先级高,不一定先执行,看CPU。但是权重会更大一点

守护(daemon)线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如:后台记录操作日志,监控内存,垃圾回收等待

thread.setDeamon(true)设置线程为守护线程,默认为false表示用户线程

用户线程执行完后需要一段时间虚拟机才会停止

线程同步

并发:同一对象被多个线程同时操作

形成条件:队列+锁(synchronized) 才能保证安全性

问题:多线程竞争下损失性能。 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题

不加锁:多个线程获得一样的内存,都认为可以取票,导致最后剩余票数为负数

同步方法

synchronized相当于一个修饰符。可以生成同步方法和同步块

缺陷:将一个大的方法声明为synchronized会影响效率

方法里面需要修改的内容才需要锁

synchronized非静态同步方法锁的其实是this

以下为一个取钱的代码,不进行同步的话会存在错误

同步方法 加上synchronized修饰方法

同步块synchronized(同步监视器){ 代码 } 同步监视器可以是任何对象,推荐使用共享资源作为同步监视器

同步方法的同步监视器就是this,就是这个对象本身或者是class

如果用同步方法锁住run方法,实际上是synchronized(run),代指的是他所在的类Drawing。Drawing有两个对象you和girl,并不是被多个线程同时操作的对象,且Drawing类不涉及增删改,所以没有用(举实际离子的话就是把银行锁住了,两个人排队进了银行,但是没有解决取钱冲突的问题。应该锁住他们两个同时操作的银行卡账户)。

所以采用同步块,将变化的对象account锁住,同时将关于account增删改的代码移入同步块中

package demo04;

public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");

        Drawing you = new Drawing(account,50,"你");
        Drawing girl = new Drawing(account,100,"GIRL");

        you.start();
        girl.start();
    }
}

class Account{
    int money;
    String name;

    public Account(int money,String name) {
        this.money = money;
        this.name = name;
    }
}

class Drawing extends Thread{
    Account account;
    int darwingMoney;
    int nowMoney;

    public Drawing(Account account,int darwingMoney,String name){
        super(name);
        this.account=account;
        this.darwingMoney=darwingMoney;
    }

    @Override
    public void run() {
        if(account.money-darwingMoney<0){
            System.out.println(Thread.currentThread().getName()+"钱不够,去不了");
            return;
        }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        account.money-=darwingMoney;

        nowMoney+=darwingMoney;

        System.out.println(account.name+"余额为:"+account.money);
        System.out.println(this.getName()+"手里的钱:"+nowMoney);
    }
}
//把run中的增删改代码放入同步块中
@Override
    public void run() {
        synchronized (account){
            if(account.money-darwingMoney<0){
                System.out.println(Thread.currentThread().getName()+"钱不够,取不了");
                return;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            account.money-=darwingMoney;

            nowMoney+=darwingMoney;

            System.out.println(account.name+"余额为:"+account.money);
            System.out.println(this.getName()+"手里的钱:"+nowMoney);
        }

死锁

多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,就会导致两个以上的线程都在等待对方释放资源。即某一个同步块同时拥有两个以上对象的锁。

if (choice == 0) {
            synchronized (lipstick) {//获得口红的锁
                System.out.println(this.girlname + "获得口红的锁");
                Thread.sleep(1000);
            }
            synchronized (mirror) {//一秒钟后获得镜子的锁
                System.out.println(this.girlname + "获得镜子的锁");
            }
        } else {
            synchronized (mirror) {//获得镜子的锁
                System.out.println(this.girlname + "获得镜子的锁");
                Thread.sleep(2000);
                }
            synchronized (lipstick) {//一秒钟后获得口红的锁
                System.out.println(this.girlname + "获得口红的锁");

这样不会出现死锁,choic为0的情况获得口红锁将其执行完,然后释放口红锁。

如果将镜子锁写到口红锁内部,那么在执行完输出口红语句后由于无法获得已经被else语句执行体锁上的镜子所以无法走完程序,进而无法释放口红锁

Lock锁(接口)

//定义Lock锁
    private final ReentrantLock lock=new ReentrantLock();
lock.lock();//加锁
try{
               
}finally {
    //解锁
     lock.unlock();
}

lock是显式锁,要手动开启和关闭

lock只有代码块锁,没有方法锁

优先使用顺序:lock>同步代码块>同步方法

线程协作 生产者消费者模式

wait( )线程一直等待,直到其他线程通知,与sleep不同,会释放锁

wait( long timeout) 指定等待的毫秒数

notify( ) 唤醒一个处于等待状态的线程

notifyAll( ) 唤醒同一个对象上所有调用wait方法的线程,优先级别高的线程优先调度

1.管程法 设置一个数据缓存区,生产者将生产好的数据放入缓存区中,消费者从缓存区拿出数据

线程池

corePoolSize:核心池大小

maximumPoolSize:最大线程数

keepAliveTime:线程没有任务时最多保持多长时间后会终止

目前讲的不是很清晰

标签:同步,java,Thread,对象,接口,线程,多线程,方法
From: https://www.cnblogs.com/zaughtercode/p/17062945.html

相关文章

  • javaWeb
    在java中,动态web资源开发的技术统称为JavaWeb一些默认tomcat:8080mysql:3306http:80https:443默认的主机名:loaclhost->127.0.0.1默认网站应用存放的位置:webapps......
  • javaScript
    JavaScript是一门流行脚本快速入门跟css一样,可以直接写在html中,放在script标签中alert可以弹出弹窗,内容用单引号引入的时候一定要成对出现,不能自闭和基本语法入门......
  • java基础
    p460-470List类子类的底层逻辑JAVA基础快捷键ctrl+alt+L整理代码shift+F10运行ctrl+B定位找到方法ctrl+H查看一个类的层级关系ctrl+d复制当前代码项向下shift......
  • java io流
    起因:学习网编,发现里面的课程大量用到了io的知识,十分影响学习,所以转战io何为“流”流:数据在数据源(文件)和程序(内存)之间经历的路径输入流:数据从数据源(文件)到程序(内存)的路径......
  • java 多态学习笔记
    因为在想去一个家乡的小国企,每个月五六千块钱或许也不错,所以懈怠了学习。但是论语中有说:取乎其上,得乎其中;取乎其中,得乎其下;取乎其下,则无所得矣。如果我想着只是进一个小地......
  • JavaScript 中断forEach循环
    1、使用Array.prototype.some()方法代替some()方法会在找到第一个符合条件的元素时停止循环。例如:letarray=[1,2,3,4,5];array.some(function(element,inde......
  • java HTML5
    HTML超文本标记语言W3C万维网联盟W3C标准包括:结构化标准语言(HTML,XML)表现标准语言(CSS)行为标准(DOM,ECMAScropt) 网页基本信息使用<!--注释内容-->进行注释......
  • java IO流
    起因:学习网编,发现里面的课程大量用到了io的知识,十分影响学习,所以转战io何为“流”流:数据在数据源(文件)和程序(内存)之间经历的路径输入流:数据从数据源(文件)到程序(内存)的路径......
  • java CSS3
    CSS层叠级联样式表快速入门CSS可以在html文件中写,写在<style>中,一般style写在head中(HTML,CSS没有分离)<style> h1(选择器){可以设置h1的属性(声明,分号结尾)......
  • javaWeb
    在java中,动态web资源开发的技术统称为JavaWeb一些默认tomcat:8080mysql:3306http:80https:443默认的主机名:loaclhost->127.0.0.1默认网站应用存放的位置:webapps......