多线程---java

读前说明:

由于是多线程编程,CPU调度线程的随机性,运行结果,每次都有可能不同,故在此没有截图程序的运行结果。读者可自行运行程序,检验结果。
本文着重介绍java多线程编程的基础---耐心看完,就会有满满的收获

多线程

1.如果程序只有一条执行路径(main),那么该程序就是单线程程序。
2.如果程序有多条执行路径,那么该程序就是多线程程序。
image.png
11.Java程序的运行原理:
由java命令启动JVM,JVM启动就相当于启动了一个进程(操作系统windows层面看),
接着由该进程创建一个主线程去调用main方法。

思考题:jvm虚拟机的启动是单线程的还是多线程的?
多线程
原因是:垃圾回收线程也要先启动,否则很容易出现内存溢出。
现在的垃圾回收线程加上前面的主线程,最少启动了两个线程,所以,jvm 的启动其实是多线程的。
12.java是不能直接调用系统功能的(需要使用C/C++语言)。
进程是由系统创建的,所以我们应该去调用系统功能创建一个进程(C/C++语言实现)
image.png

  1. 实现Runnable接口

多个人抢CPU的执行权去干自己的活。
多个人抢CPU的执行权去干共同的活。---线程安全问题
多线程---java_第1张图片
Synchronized关键字放在权限修饰符后。public synchronized void 方法名(){}

Collections 集合工具类(以下三个方法均为静态方法)

  1. synchronizedList
    返回指定列表支持的同步(线程安全的)列表。
  2. synchronizedMap
    返回由指定映射支持的同步(线程安全的)映射。
  3. synchronizedSet
    返回指定 set 支持的同步(线程安全的)set。
    多线程---java_第2张图片

线程安全的类StringBuffer、Vector、HashTable
多线程---java_第3张图片

public class MyThread {
        public static final MyThread my1=new MyThread();
        public static final MyThread my2=new MyThread();
}
public class DieLock extends Thread{
    private boolean flag;
     public DieLock(boolean flag) {
         this.flag=flag;
     }
        
    @Override
    public void run() {
        while(true) {
            if(flag) {
                synchronized(MyThread.my1) {
                    System.out.println("if 1");
                    synchronized(MyThread.my2) {
                        System.out.println("if 2");
                    }
                }
            }else {
                synchronized(MyThread.my2) {
                    System.out.println("else 1");
                    synchronized(MyThread.my1) {
                        System.out.println("else 2");
                    }
                }
            }
        }
    }
}
public class DieLockTest {

    public static void main(String[] args) {
        DieLock t1=new DieLock(true);
        DieLock t2=new DieLock(false);
        t1.start();
        t2.start();
    }

}

image.png

生产者与消费者问题:
多线程---java_第4张图片

public class Student {
    String name;
    int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class SetStudent implements Runnable {
    Student student;
    public SetStudent(Student student) {
        this.student = student;
    }
    
    @Override
    public void run() {
        student.setName("wxz");
        student.setAge(20);

    }
}
public class GetStudent implements Runnable {
    Student student;
    public GetStudent(Student student) {
        this.student = student;
    }
    @Override
    public void run() {

        System.out.println(student.getName()+"---"+student.getAge());
    }
}
public class StudentTest {
    public static void main(String[] args) {
        Student s1=new Student();
        SetStudent s=new SetStudent(s1);
        GetStudent g = new GetStudent(s1);
        Thread t1=new Thread(s);
        Thread t2=new Thread(g);
        t2.start();
        t1.start();
    
    }
}

一种结果:
多线程---java_第5张图片

不同种类线程加的锁必须是同一把锁。即锁对象必须是同一个,本例中的共享资源(student对象就是同一个对象,因此可以作为锁对象)。

多线程---java_第6张图片
s.wait(); //t2就等待了。此时立即释放锁,将来是从这里醒过来的。
s.notify();//唤醒并不表示立马可以执行,必须还得抢CPU的执行权。

public class Student {
    String name;
    int age;
    boolean flag;//默认值为false
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}
public class SetStudent implements Runnable {
    Student student;
    private int x=0;
    public SetStudent(Student student) {
        this.student = student;
    }

    @Override
    public void run() {

        while(true){
            synchronized(student) {
                if(student.flag) {
                    try {
                        student.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(x % 2 == 0) {
                    student.setName("wxz");
                    student.setAge(20);
                    //System.out.println("生产");

                }else {
                    student.setName("summer");
                    student.setAge(10);
                    //System.out.println("生产");
                }
                x++;
                student.flag=true;                
                student.notify();//唤醒并不表示立马可以执行,必须还得抢CPU的执行权
            }
        }

    }
}
flag标志的作用:表示是否有生产的资源, 若有便可以通知消费者消费。
若没有便可通知生产者生产。
public class GetStudent implements Runnable {
    Student student;
    public GetStudent(Student student) {
        this.student = student;
    }
    @Override
    public void run() {
        while(true){
            synchronized(student) {
                if(!student.flag) {
                    try {                        
                        student.wait();//t2等待,立即释放锁,将来是从这里醒过来的
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //System.out.println("消费");
                System.out.println(student.getName()+"---"+student.getAge());                
                student.flag=false;
                student.notify();
                
            }
        }
    }
}
public class StudentTest {

    public static void main(String[] args) {
        Student s1=new Student();
        SetStudent s=new SetStudent(s1);
        GetStudent g = new GetStudent(s1);
        Thread t1=new Thread(s);
        Thread t2=new Thread(g);
        t2.start();
        t1.start();
    }
}

多线程---java_第7张图片

生产者与消费者问题的最终版代码

把Student的成员变量给私有化,
把设置和获取的操作封装成了功能,并加了同步。
设置或者获取的线程里面之需要调用方法即可。
package com.study;

public class Student {
    private String name;
    private int age;
    private boolean flag;//默认值为false

    // 方法锁对象为默认的this
    // 那个对象调用set方法,那么this指得就是那个对象。由于这里的set和get方法都是由student对象来调用的,
    // 故这里的this指的是student对象,因此锁对象一样。能解决线程安全问题。
    public synchronized void set(String name,int age) {
        
        if(this.flag) {
            //System.out.println(this+"=========================================");
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name=name;
        this.age=age;
        this.flag=true;
        this.notify();
    }

    public synchronized void get() {
        if(!this.flag) {
            //System.out.println(this+"+++++++++++++++++++++++++++++++++++++++++");
            try {
                this.wait();
            } catch (InterruptedException e) {
                
            }
        }
        System.out.println(this.name+"---"+this.age);
        this.flag=false;
        this.notify();    
    }    
}
package com.study;

public class SetStudent implements Runnable {
    Student student;
    private int x=0;
    public SetStudent(Student student) {
        this.student = student;
    }

    @Override
    public void run() {

        while(true){
            if(x%2==0) {
                student.set("wxz",10);
            }else {
                student.set("summer",20);
            }
            x++;
        }
    }
}
package com.study;

public class GetStudent implements Runnable {
    Student student;
    public GetStudent(Student student) {
        this.student = student;
    }
    @Override
    public void run() {
        while(true){            
            student.get();                            
        }    
    }
}
package com.study;

public class StudentTest {

    public static void main(String[] args) {
        Student s1=new Student();

        SetStudent s=new SetStudent(s1);
        GetStudent g = new GetStudent(s1);
        
        Thread t1=new Thread(s);
        Thread t2=new Thread(g);
        t2.start();
        t1.start();
    }
}

线程池

多线程---java_第8张图片

package com.executors;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 线程池有五个线程,来了六个任务,只能等一个线程干完,还了链接之后才可以开始最后一个任务。

public class ExecutorsTest {

    public static void main(String[] args) {
        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);
        newFixedThreadPool.submit(new Task());
        newFixedThreadPool.submit(new Task());
        newFixedThreadPool.submit(new Task());
        newFixedThreadPool.submit(new Task());
        newFixedThreadPool.submit(new Task());
        newFixedThreadPool.submit(new Task());
        newFixedThreadPool.shutdown();//关闭线程池
    }

}
package com.executors;

public class Task implements Runnable {

    @Override
    public void run() {
        for (int i = 0;i <10 ;i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }

}

定时器

多线程---java_第9张图片

package com.timer;

import java.util.Timer;

public class TimerTest {

    public static void main(String[] args) {
        Timer timer=new Timer();
        timer.schedule(new MyTask(timer), 5000);
    }

}
package com.timer;

import java.util.Timer;
import java.util.TimerTask;

public class MyTask extends TimerTask{
    
    private Timer timer;
    public MyTask() {
        
    }
    public MyTask(Timer timer) {
        this.timer=timer;
    }
    @Override
    public void run() {
        System.out.println("到点了");    
        timer.cancel();
    }

}

多线程---java_第10张图片

package com.timer;

import java.util.Timer;

public class TimerTest {

    public static void main(String[] args) {
        Timer timer=new Timer();
        timer.schedule(new MyTask(), 1000,1000);
    }

}
package com.timer;

import java.util.Date;
import java.util.TimerTask;

public class MyTask extends TimerTask{

    @Override
    public void run() {
        System.out.println(new Date());    
    }

}

多线程---java_第11张图片

定时删除指定目录下的资源:

package com.timer;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;

public class DelectTest {

    public static void main(String[] args) throws ParseException {
        Timer timer=new Timer();
        String date="2020-12-18 16:48:00";
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date time=simpleDateFormat.parse(date);
        timer.schedule(new DeleteFolder(), time);
    }

}
package com.timer;

import java.io.File;
import java.util.TimerTask;

public class DeleteFolder extends TimerTask{

    @Override
    public void run() {
        File file = new File("E:/test");
        deleteFolder(file);
    }

    private void deleteFolder(File file) {
        if(file != null) {
            File[] listFiles = file.listFiles();
            for(File f:listFiles) {
                if (f.isDirectory()) {
                    deleteFolder(f);
                }else {
                    System.out.println(f.getName());
                    f.delete();                    
                }
                
            }
            file.delete();
        }    
    }
        
}

多线程---java_第12张图片

常见面试题:

多线程---java_第13张图片

你可能感兴趣的:(java)