JAVA学习笔记:多线程

常见概念

线程与进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间
线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程
线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程

线程调度

分为分时调度和抢占式调度,java使用的是抢占式调度,每个线程拥有优先级,互相竞争cpu使用权
CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核新而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。

同步与异步

同步:排队执行 , 效率低但是安全.
异步:同时执行 , 效率高但是数据不安全.

并发与并行

并发:指两个或多个事件在同一个时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。

实现多线程的两个方法

Tread继承

重写run方法,然后在需要的地方创建实例并调用start方法开始线程。

public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("线程使用了");
    }
}

在这里插入图片描述

实现Runable

public class Test {
    public static void main(String[] args) {


        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread);
        thread.start();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println("线程使用了");
    }
}

在这里插入图片描述

实现Runable与继承Thread相比的优势

1.通过创建任务,然后给线程分配实现更适合各个线程同时执行相同任务的情况.
2.可以避免单继承的局限性
3.任务与线程本身是分离的,提高程序健壮性
4线程池接受Runable类型的任务不接受Thread类型,操作更方便

常用方法

变量和类型方法描述
static ThreadcurrentThread()返回对当前正在执行的线程对象的引用。
longgetId()返回此Thread的标识符。
StringgetName()返回此线程的名称
static ThreadcurrentThread()返回对当前正在执行的线程对象的引用。
intgetPriority()返回此线程的优先级。
voidinterrupt()中断此线程。
voidsetDaemon​(boolean on)将此线程标记为 daemon线程或用户线程。
voidsetName​(String name)将此线程的名称更改为等于参数 name 。
voidsetPriority​(int newPriority)更改此线程的优先级。
static voidsleep​(long millis)导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。
static voidsleep​(long millis, int nanos)导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统定时器和调度程序的精度和准确性。
voidstart()导致此线程开始执行; Java虚拟机调用此线程的run方法。
public class Test {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread t = new Thread(myThread);
        t.setName("守护线程:");
        t.setDaemon(true);
        t.start();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    return;
                }
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }
}

在这里插入图片描述

线程安全

线程安全问题

指多个线程同时执行一段逻辑时,判断的数据可能和执行前的数据发生变化,造成结果错误

public class Test {
    public static void main(String[] args) {
        MyThread run = new MyThread();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
        }
    }

    class MyThread implements Runnable {
        int count = 10;
        @Override
        public void run() {
            while (count > 0) {

                System.out.println(Thread.currentThread().getName() + "正在出票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                --count;
                System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);

            }
        }
    }

在这里插入图片描述

三种解决方案

同步代码块

用synchronized(Object object){要同步的代码块} 例如上例中的问题代码

public class Test {
    public static void main(String[] args) {
        MyThread run = new MyThread();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
        }
    }

    class MyThread implements Runnable {
        Object o = new Object();
        int count = 10;
        @Override
        public void run() {
            while (true) {
                synchronized (o) {
                    if (count > 0) {
                        System.out.println(Thread.currentThread().getName() + "正在出票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        --count;
                        System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
                    } else {
                        break;
                    }
                }
            }
        }
    }

在这里插入图片描述

同步方法

使用synchronized关键字修饰方法

public class Test {
    public static void main(String[] args) {
        MyThread run = new MyThread();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
        }
    }

    class MyThread implements Runnable {
        Object o = new Object();
        int count = 10;
        @Override
        public void run() {
            while (true) {
                boolean flag = sale();
                if (!flag) {
                     break;
                }
            }

        }
        public synchronized boolean sale() {
            if (count > 0) {
                System.out.println(Thread.currentThread().getName() + "正在出票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                --count;
                System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
            } else {
                return false;
            }
            return true;
        }
    }

在这里插入图片描述

显式锁Lock

声明一个ReentrantLock对象,在要同步的代码开头使用lock()方法,结尾处使用unLock()方法:

public class Test {
    public static void main(String[] args) {
        MyThread run = new MyThread();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
        }
    }

    class MyThread implements Runnable {
        Object o = new Object();
        int count = 10;
        Lock l = new ReentrantLock();

        @Override
        public void run() {
            while (true) {
                l.lock();
                if (count > 0) {
                    System.out.println(Thread.currentThread().getName() + "正在出票");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    --count;
                    System.out.println(Thread.currentThread().getName() + "出票成功,余票:" + count);
                } else {
                    break;
                }
                l.unlock();
            }
        }

    }

在这里插入图片描述

线程死锁

两个线程互相访问同步的方法或资源时,会造成线程死锁

在开发时,如果一个线程已经有了一个锁,则不要调用另一个可能产生锁的对象或方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值