java基础复习(二十二)

1.什么是线程

  • 线程是 程序执行的一条路径,一个进程中可以包含多条线程
  • 多线程并发执行可以提高程序的效率,可以同时完成多项工作

2.多线程的应用场景

  • 红蜘蛛同时恭喜啊经屏幕给多个电脑
  • 迅雷开启多条线程一起下载
  • QQ同时和多个人一起视频
  • 服务器同时处理多个客户端请求

多线程并行和并发的区别

  • 并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要 多核CPU)
  • 并发是指两个任务都请求运行,而处理器值能接受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
  • 比如,我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙聊,这就叫并行
  • 如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再跟乙聊。这就叫做并发。

多线程(java程序运行原理和JVM的启动是多线程的吗)

Java程序运行原理:

  • Java命令会启动java虚拟机,启动JVM,等于启动一个应用程序,也就是启动一个进行。该进程会自动启动一个主线程,然后主线程去调用某个类的main方法。

JVM的启动是多线程的吗

  • JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

多线程(多线程程序实现的方式)

1.继承Thread

  • 定义类继承Thread
  • 重写run方法
  • 把新线程要做的事写在run方法中
  • 创建线程对象
  • 开启新线程,内部会自动执行run方法
class MyThread extends Thread {//1.继承Thread
    public void run(){//2.重写Run方法
        for(int i = 0 ;i < 1000 ;i++){//将要执行的代码写在run方法中
            System.out.println("aaaaaaaaaaa");
        }
        
    }
}

public static void main(String[] args){
    MyThread mt = new MyThread();//4.创建Thread类的子类对象
    mt.start();//开启线程 调用run方法进行跑
    //mt.run();
    
    for( int i = 0 ; i < 1000 ;i++){
        System.out.println("bbbbbbbbbbbbbbbbbbb");
    }
}

多线程的实现方式_2 (实现Runnable的原理)

  • 查看源码

    1. 看Thread类的构造函数,传递了Runnable接口的引用
    2. 通过init()方法找到传递的target给成员变量的target复制
    3. 查看run方法,发现run方法中有判断,如果target不为null就会调用Runnable接口子类对象的run方法//
class MyRunnable implements Runnable {//1.自定义类实现Runnable接口
    @Override
    public void run () {//2.重写run方法
        for(int i = 0;i <3000; i++){//3.将要执行的代码,写在run方法中
            System.out.println("aaaaaaaaaa");
        }
    }
}

两种方式的区别

a.继承Thread:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法

b.实现Runnable:构造函数中传入了Runnable的引用,成员变量记住了它,start()调用run()方法时内部判断成员变量Runnable的引用是否为空,不为空编译时看的是Runnable的run()方法,运行时执行的是子类的run()方法

  • 继承Thread

    • 好处是:可以直接使用Thread类中的方法,代码简单。
    • 弊端是:如果已经有了父类,就不能用这种方法。
  • 实现Runnable接口

    • 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的。
    • 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂。

匿名内部类实现线程的两种方式

  • 继承Thread
new Thread() {
    public void run() {
        for(int i = 0 ; i<1000 ;i++){
            System.out.println("aaaaa");
        }
    }
}.start();

new Thread (new Runnable(){
    public void run() {
        for(int i = 0;i < 1000 ; i++) {
            System.out.println("bb");
        }
    }
}).start();

多线程(获取名字和设置名字)

new Thread() {
    public void run() {
        this.setName("zhangsan");
        System.out.println(this.getName() + "aaaaa");
    }
}.start();

new Thread() {
    public void run() {
        this.setName("lisi");
        System.out.println(this.getName() + "....bb");
    }
}.start();

休眠线程

Thread.slepp();//毫秒值;纳秒值;

for(int i = 20 ; i > 0 ;i--){
    Thread.sleep(1000);//需要抛出异常InterruptedException
    System.out.println(i);
}

守护线程

setDaemon 设置一个线程为守护线程,该线程不会单独执行,当其他非守护线程都执行结束后,自动退出。

Thread t1 = new Thread(){
    public void run() {
        for (int i = 0 ;i < 2; i++){
            System.out.println(getName()+ "...AAAAA");
        }
    }
}

Thread t2 = new Thread(){
    public void run() {
        for (int i = 0 ;i < 50; i++){
            System.out.println(getName()+ "...bbbb);
        }
    }
}
t2.setDaemon(true);//当传入true就是意味着设置为守护线程
t1.start();
t2.start();  
                               

加入线程

join(),当线程暂停,等待指定的线程执行结束后,当前线程再继续

final Thread t1 = new Thread(){//匿名内部类在使用过程中一定要用final来修饰
    public void run() {
        for (int i = 0 ;i < 40; i++){
            System.out.println(getName()+ "...AAAAA");
        }
    }
}

Thread t2 = new Thread(){
    public void run() {
        for (int i = 0 ;i < 50; i++){
            if( i == 2) {
                try {
                t1.join(1);//插队指定的时间,过了指定的时候后,两条线程交替执行
                }catch(Exception e){
                    e.printstack();
                }
            }
            System.out.println(getName()+ "...bbbb);
        }
    }
}

插队

礼让线程

yield让出CPU

for( int i =1 ; i <= 1000 ;i++){
    if( i % 10 == 0){
        Thread.yield(); //让出CPU
        System.out.println(getName() + "..."+i);
    }
}

设置线程的优先级

最小1,最大10,默认5

Thread t1 = new Thread(){
    public void run() {
        for (int i = 0 ;i < 1000; i++){
            System.out.println(getName()+ "...AAAAA");
        }
    }
}

Thread t2 = new Thread(){
    public void run() {
        for (int i = 0 ;i < 1555; i++){
            System.out.println(getName()+ "...NBBBNBNNBNBN");
        }
    }
}
//t1.setPriority(1);
//t2.setPriority(10);//设置最大优先级

t1.setPriority(Thread.MIN_PRIORITY);//设置最小的线程优先级
t2.setPriority(Thread.MAX_PRIORITY);//设置最大的线程优先级

t1.start();
t2.start();

多线程的同步代码块

1.什么情况下需要同步

  • 当多线程并发,有多段代码同时执行时,我们希望一段代码执行的过程中CPU不要切换到其他线程工作,这时就需要同步。
  • 如果两端代码是同步的,那么同一时间只能执行一段,在一段代码没执行结束之前,不会执行另外一段代码。

2.同步代码块

  • 使用synchronized关键字加上一个锁对象来定义一段代码,这就叫做同步代码块
  • 多个同步代码块如果使用相同的锁对象,那么他们就是同步的
class Printer {
    public void print1() {
        synchronized(d) {//同步代码块,锁机制
        System.out.print("黑");
        System.out.print("马");
        System.out.print("程");
        System.out.print("序");
        System.out.print("员");
        System.out.print("\r\n");
        }
    }
    public void print2() {
        synchronized(d) {//锁对象不能用匿名对象,不过是任意数据的
            System.out.print("传");
            System.out.print("智");
            System.out.print("播");
            System.out.print("客");
            System.out.print("\r\n");
        }
    }
}

Printer p = new Printer();
new Thread() {
    public void run() {
        while(true) {
            p.print1();
        }
    }
}

同步方法

public synchronized void print1() {
       //非静态的同步方法的锁对象是什么
       //非静态的同步方法的锁对象是this
    //静态的同步方法的锁对象是什么?
    //是该类的字节码对象
        System.out.print("黑");
        System.out.print("马");
        System.out.print("程");
        System.out.print("序");
        System.out.print("员");
        System.out.print("\r\n");
}
public synchronized void print2() {
            System.out.print("传");
            System.out.print("智");
            System.out.print("播");
            System.out.print("客");
            System.out.print("\r\n");
}                    
public void print2() {
        synchronized(this) 
            System.out.print("传");
            System.out.print("智");
            System.out.print("播");
            System.out.print("客");
            System.out.print("\r\n");
        }
}                    

线程安全问题

多线程并发操作

class Ticket extends Thread {
    private static int ticket = 100;
    cc
    public void run() {
        while(true) {
            synchronized(Ticket.class){
            if(ticket == 0){
                break;
            }
                
            }
            
        }
    }
}

多次启动一个线程是非法的

死锁

多线程同步的时候

Vector线程安全的 ==== ArrayList是线程不安全的

StringBuffer是线程安全的,StringBuilder是线程不安全的

Hashtable是线程安全的HashMap是线程不安全的

本文链接:

https://heyzen.club/index.php/J/271.html
1 + 7 =
快来做第一个评论的人吧~