Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程

导学了解

什么是进程?

进程:程序的基本执行实体

更加通俗的讲:一个软件执行后,它就是一个进程,绿色的内容都是一个进程。

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第1张图片

什么是线程?

线程是操作系统能够进行运算调度的最小单位。它被包含在进程当中,是进程中的实际运作单位。

可以这样理解: 用没有用过360安全卫士,它上面的每个功能都相当于进程,很多进程能够同时的运行,并且互相没有产生问题。进程类似于应用中互相独立,可以同时运行的功能。很多的线程合在一起就形成了多线程。

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第2张图片

什么是多线程?

Java多线程是指在Java程序中同时运行多个线程,每个线程都可以独立执行不同的任务。Java多线程可以提高程序的并发性和响应性,使得程序可以同时处理多个任务,提高程序的效率。Java中的多线程可以通过继承Thread类或实现Runnable接口来创建线程,也可以使用线程池来管理线程。同时,Java提供了丰富的多线程API,如synchronized关键字、wait()和notify()方法等,来帮助开发者更好地控制线程的并发访问。

实现多线程的三种方式:

方法一:继承Thread类:

通过重写父类Thread方法中的run方法实现线程

注意:线程的开启是通过使用start方法来开启线程,而并非是通过使用调用run方法,通过类的对象去调用run方法,只能是一个普通的调用,并不能开启线程。

代码实现: 

package thread_study;

public class demo1 {
    public static void main(String[] args) {
        MyThread1 thread = new MyThread1();
        MyThread1 thread2 = new MyThread1();
        thread.setName("线程一");
        thread2.setName("线程而");
        //注意:这里的线程开发则是通过start方法去开启,并非是通过调用run方法,调用run方法则是普通的调用
        thread.start();
        thread2.start();

    }
}
class MyThread1 extends Thread{
    /*
        开启线程的第一种方法:
        定义个类去继承线程类Thread
        重写类中的run方法
        创建子类的对象,并且去开启线程
     */
    @Override
    public void run() {
        for (int i=0;i<10;i++){
            System.out.println("这是"+getName()+"的内容输出");
        }
    }
}

控制台输出:

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第3张图片

方法二:通过实现Runnable接口

代码实现

package thread_study;

public class demo2 {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread thread = new Thread(myThread2);
        Thread thread2 = new Thread(myThread2);
        thread.setName("线程一");
        thread2.setName("线程二");
        thread.start();
        thread2.start();

    }
}
class MyThread2 implements Runnable{
    /*
        开启线程的第二种方法:
        定义个类实现R
        重写类中的run方法
        创建子类的对象,并且去开启线程
     */
    @Override
    public void run() {
        for (int i=0;i<10;i++){
//            Thread thread = Thread.currentThread();
            System.out.println("这是"+Thread.currentThread().getName()+"的内容输出");
        }
    }
}

方法三:继承Callable

注意:这个方法拥有返回值

package thread_study;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

//第三种方法去实现线程
public class MyThread3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
            多线程实现的第三种方法:可以接收到线程运行的结果
            通过实现Callable接口,重写call方法
            然后通过创建FutureTask对象(通过此类可以实现对多线程运行结果的管理
         */
        MyThread_test myThread_test = new MyThread_test();
        FutureTask futureTask  = new FutureTask<>(myThread_test);
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());

    }

}
class MyThread_test implements Callable {

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i <= 100; i++) {
            sum =sum +i;
        }
        return sum;
    }
}

多线程常用的方法讲解 

setPriorit(int 值):设置优先级

可以设置线程的优先顺序,优先级高的线程会优先去执行,但是这种方法的设置,并不意味着优先级高的一定比优先级底的先执行完,因为在线程执行是抢占式,谁先抢到谁先去执行,所以说优先级高的并不是一定的比线程优先级低的先行执行完成。

代码实现:

设置:线程二的优先级比线程的一的优先级高

package thread_study;

public class MyThread04 {
    public static void main(String[] args) {
        Thread04_test thread04_test= new Thread04_test();
        Thread thread = new Thread(thread04_test,"线程一");
        Thread thread2 = new Thread(thread04_test,"线程二");
        //获取当前线程的优先级
//        System.out.println(Thread.currentThread().getPriority());
        //设置进程的优先级默认为5 1最小 10最大
        thread.setPriority(1);
        thread2.setPriority(10);
        thread.start();
        thread2.start();
    }
}
class Thread04_test implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"@"+i);
        }
    }
}
/*
* 线程优先级低的可能比优先级的高的线程先行执行完,只是这中的概率比较低,但是还是有一种概率发生。如果不进行任何的设置,那么这个线程的默认优先级数值为5
*
* */

运行结果:

大概率的情况下:线程二先行执行完,然后线程一再执行完

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第4张图片

小概率的情况下:线程二后执行完,线程一先行执行完

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第5张图片

守护线程

守护线程:可以理解为当一个线程结束时,守护线程也会陆续的结束 ,qq聊天界面,有着聊天和传输文件的功能,聊天是一个线程,传输文件也是一个线程,但是当一个qq聊天界面关闭时,那么传输文件的哪个界面,也就关闭了 * 守护线程当线程结束时,那么守护线程则没有没有存在的必要了,但是它不会立刻的结束,他会慢慢的结束。

案例实现线程二对线程一的守护,当线程一结束时,他的守护线程二也会陆陆续续的停掉

代码实现: 

package thread_study;

public class MyThread05 {
    public static void main(String[] args) {
        /*
        *   守护线程:可以理解为当一个线程结束时,守护线程也会陆续的结束
        *   qq聊天界面,同时聊天和传输文件,聊天是一个线程,传输文件也是一个线程,但是当一个qq聊天界面关闭时,那么传输文件的哪个界面,也就关闭了
        *   守护线程当线程结束时,那么守护线程则没有没有存在的必要了,但是它不会立刻的结束,他会慢慢的结束
        *
        * */
        //案例实现线程二对线程一的守护,当线程一结束时,他的守护线程二也会陆陆续续的停掉
        Thread05_demo1 thread05_demo1 = new Thread05_demo1();
        Thread05_demo2 thread05_demo2 = new Thread05_demo2();

        thread05_demo1.setName("线程一");
        thread05_demo2.setName("线程二");
        //把线程二设置成守护线程
        thread05_demo2.setDaemon(true);

        thread05_demo1.start();
        thread05_demo2.start();
    }
}

class Thread05_demo1 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}
class Thread05_demo2 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

运行结果:

线程二守护线程一,当线程一执行完之后,线程二就陆陆续续的结束,并不能直接的结束

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第6张图片

 yield()出让线程

出让线程:Java的线程时抢占式,多线程过程中,谁先抢到线程,谁就会先执行 *

也可以通过yield出让本线程的执行权,出让执行权,但是出让这个机会,出让执行权的线程依旧可以再次的抢夺,可以通过此方法实现尽可能的均匀 *

静态方法,可以通过类去直接的调用

代码实现

package thread_study;

public class MyThread06 {
    public static void main(String[] args) {
        /*
        * 出让线程:Java的线程时抢占式,多线程过程中,谁先抢到线程,谁就会先执行
        * 也可以通过yield出让本线程的执行权,出让执行权,但是出让这个机会,出让执行权的线程依旧可以再次的抢夺,可以通过此方法实现尽可能的均匀
        * 静态方法,可以通过类去直接的调用
        * */
        MyThread06_test myThread06_test1 = new MyThread06_test();
        MyThread06_test myThread06_test2 = new MyThread06_test();

        myThread06_test1.setName("线程一");
        myThread06_test2.setName("线程二");

        myThread06_test1.start();
        myThread06_test2.start();
    }
}

class MyThread06_test extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
            //出让当前CPU的执行权
            Thread.yield();
        }
    }
}

join方法:实现线程的插入(通俗的讲就是插队)

插入线程,在一个线程的前面,在插入一个线程

通过join方法来实现

main方法默认的情况下也是一个程序

在main方法去执行程序,然后再通过join方法去再main方法前添加一个程序

代码实现

package thread_study;

public class MyThread07 {
    public static void main(String[] args) throws InterruptedException {
        /*
            插入线程,在一个线程的前面,在插入一个线程
            通过join方法来实现
            main方法默认的情况下也是一个程序
            在main方法去执行程序,然后再通过join方法去再main方法前添加一个程序
        * */
//      通过join方法实现MyThread07_test线程的插入
        MyThread07_test myThread07_test = new MyThread07_test();
        myThread07_test.setName("线程");
        myThread07_test.start();
        myThread07_test.join();
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }

}

class MyThread07_test extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"@"+i);
        }
    }
}

运行结果

线程插队成功

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第7张图片

锁:synchronized

//同步代码块

//给线程添加一个锁,保证的是只有一个线程去执行,当代码完全执行完毕后,再释放锁,不会出现数据的重复,和超出范围值

//注意锁的对象必须是唯一的,可以通过字节码对象,因为带idea中类的创建必须是唯一的

* 实现三个售票点,正在销售,总共有100张票

* 在正常的开发过程中,几个线程同时执行代码,那么在同一时间而言,就有可能有多个线程去执行同一行代码

* 这样就容易出现代码的重复,还会容易出现,超出范围等问题,锁的产生帮助我们去解决这个问题 

 代码实现

package thread_study;

public class MyThread08 {

    public static void main(String[] args) {
        /*
        * 实现三个售票点,正在销售,总共有100张票
        * 在正常的开发过程中,几个线程同时执行代码,那么在同一时间而言,就有可能有多个线程去执行同一行代码
        * 这样就容易出现代码的重复,还会容易出现,超出范围等问题,锁的产生帮助我们去解决这个问题
        * */

        MyThread08_test myThread08_test1 = new MyThread08_test();
        MyThread08_test myThread08_test2 = new MyThread08_test();
        MyThread08_test myThread08_test3 = new MyThread08_test();

        myThread08_test1.setName("售票点一");
        myThread08_test2.setName("售票点二");
        myThread08_test3.setName("售票点三");

        myThread08_test1.start();
        myThread08_test2.start();
        myThread08_test3.start();

    }


}

class MyThread08_test extends Thread{
    static int ticket = 1;
    @Override
    public void run() {
        while (true){
            //同步代码块
            //给线程添加一个锁,保证的是只有一个线程去执行,当代码完全执行完毕后,再释放锁,不会出现数据的重复,和超出范围值
            //注意锁的对象必须是唯一的,可以通过字节码对象,因为带idea中类的创建必须是唯一的
            synchronized (MyThread08_test.class){
                if(ticket<=100){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName() + "正在卖第"+ticket +"票");
                    ticket ++;
                }else {
                    break;
                }
            }
        }
    }
}

输出结果:

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第8张图片

把synchronized关键字定义在方法上如何的实现

代码实现

package thread_study;

public class MyThread09 {
    public static void main(String[] args) {
        MyThread09_test myThread09_test = new MyThread09_test();
        Thread thread1 = new Thread(myThread09_test);
        Thread thread2 = new Thread(myThread09_test);
        Thread thread3 = new Thread(myThread09_test);

        thread1.setName("窗口一");
        thread2.setName("窗口二");
        thread3.setName("窗口三");

        thread1.start();
        thread2.start();
        thread3.start();
    }

}

class MyThread09_test implements Runnable{
    int ticket = 1;

    @Override
    public void run() {
        while (true){
            try {
                if (demo1()) break;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private synchronized boolean demo1() throws InterruptedException {
        if(ticket>100){
            return true;
        }else{
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + "正在卖第" +ticket + "票");
            ticket ++;
        }
        return false;
    }
}

锁二:Lock

synchronized:这个上锁是自动化,只要有线程执行了方法,就会上锁,但是只有当方法完全之后,才要释放锁

通过lock来实现,上锁和释放锁,通过我们的手动的方法去上锁和释放锁,并非像synchronized智能锁一样不需要手动的添加。

通过Lock方法实现上一个卖票的案例

package thread_study;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyThread10 {
    public static void main(String[] args) {
        /*
        * synchronized:这个上锁是自动化,只要有线程执行了方法,就会上锁,但是只有当方法完全之后,才要释放锁
        * 通过lock来实现,上锁和释放锁
        * */
        MyThread10_test myThread10_test = new MyThread10_test();
        Thread thread = new Thread(myThread10_test);
        Thread thread2 = new Thread(myThread10_test);
        Thread thread3 = new Thread(myThread10_test);
        thread.setName("线程1");
        thread2.setName("线程2");
        thread3.setName("线程3");
        thread.start();
        thread2.start();
        thread3.start();
    }
}
class MyThread10_test implements Runnable{
    static int ticket = 1;
    static Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            //上锁
            lock.lock();
            try {
                if(ticket<=100){
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + "正在卖第"+ticket +"票");
                    ticket ++;

                }else {
                    break;
                }
                
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            finally {   //把释放锁放在finally可以确保,无论如何释放锁都会被执行
                //释放锁
                lock.unlock();
                
            }
        }
    }
    }

等待唤醒机制:生产者和消费者机制

这种模式是一种十分经典的多线程协作方式,它可以让线程结果更加的均匀,假设只有两个线程的情况下,这种机制会线程一实现一次,线程二实现一次,轮流的执行。

案例实现:消费者生产者模式,生产者做出一份,那么消费者就消费一份,如果消费者没有消费完,那么生产者就需要等待,如果生产者没有生产一份,那么消费者就要等待。

代码:

生产者(Cooker)

package wait_notify;

public class Cooker extends Thread {
    @Override
    public void run() {
        while (true) {
            synchronized (Desk.object) {
                if(Desk.count==0){
                    break;
                }else {
                    if(Desk.foodlie==1){
                        try {
                            //生产者等待
                            Desk.object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        System.out.println(getName()+"要开始做饭了。。。");
                        Desk.foodlie=1;
                        //生产者唤醒消费者
                        Desk.object.notifyAll();
                    }
                }
            }
        }
    }
}

消费者: 

package wait_notify;

public class foodlie extends Thread {
    @Override
    public void run() {
        while (true){
            synchronized (Desk.object){
                if(Desk.count==0){
                    break;
                }
                else {
                    if (Desk.foodlie==0){
                        try {
                            //消费者等待
                            Desk.object.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    else {
                        Desk.count--;
                        System.out.println(getName()+"开始吃饭"+"还剩下"+Desk.count+"碗");
                        //消费者唤醒生产者
                        Desk.object.notifyAll();
                        Desk.foodlie=0;

                    }
                }
            }
        }
    }
}

控制台:相当于桌子,判断是否有食物 

package wait_notify;

public class Desk {
    //定义消费者总共吃多少量
    public static int count =10;

    //定义锁对象
    public static Object object = new Object();

    //定义桌子上是否有食物 o:表示没有 1:表示有食物
    public static int foodlie = 0;
}

测试类:

package wait_notify;

public class Test {
    public static void main(String[] args) {
            foodlie foodlie = new foodlie();
        Cooker cooker =new Cooker();

        foodlie.setName("消费者");
        cooker.setName("厨师");

        foodlie.start();
        cooker.start();
    }
}

运行结果:

Java实现多线程内容通俗易懂,一篇文章了解多线程并且能到简单的使用多线程_第9张图片 

后续会持续的更新新的学习内容

你可能感兴趣的:(Java面试,java,开发语言,1024程序员节,Thread,多线程,后端)