进程线程加锁的两种方式Object和类名.class

进程
进程的概念
进程就是正在运行的程序,他会占用对应的内存区域,由cpu进行执行与计算
进程的特点
独立性
进程是系统中独立存在的实体,他可以拥有自己的独立资源,每个进程都有自己私有的地址空间,在没有经过进程本身允许下,一个用户进程不可以直接访问其他进程的地址空间
动态性
进程与程序的区别在于,程序只是一个静态的指令集和,而进程是一个正在系统中活动的指令集和,程序加入了时间概念以后,成为进程,具有自己的生命周期和各种状态,这些概念都是程序所不具备的
并发性
多个进程可以在单个处理器cpu上并发执行,多个进程之间不会互相影响
线程
线程的概念
线程是操作系统os能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位,一个进程可以开启多个线程,其中有一个主线程来调用本进程中的其他线程。
我们看到的进程的切换,切换的也是不同进程的主线程
多线程可以让同一个进程同时并发处理多个任务,相当于扩展了进程的功能
进程与线程的关系
一个操作系统中可以有多个进程,一个进程中可以包含一个线程(单线程程序),也可以包含多个线程(多线程程序)
进程线程加锁的两种方式Object和类名.class_第1张图片
多线程的特性
随机性
串行:同一时刻一个CPU只能处理一件事
并行:同一时刻多个CPU处理多个事
CPU分时调度
1.FCFS:先来先服务算法
2.SJS:短服务算法
线程的状态
就绪状态:线程已经准备好运行,只要获得CPU,就可立即执行
执行状态:线程已经获得CPU,其程序正在运行状态
阻塞状态:正在运行的线程由于某些事件(I/O请求等)暂时无法执行的状态,即线程阻塞
三态模型
进程线程加锁的两种方式Object和类名.class_第2张图片
进程线程加锁的两种方式Object和类名.class_第3张图片
五态模型
进程线程加锁的两种方式Object和类名.class_第4张图片
进程线程加锁的两种方式Object和类名.class_第5张图片
多线程编程方案1:继承Thread类

public class TestThread1 {
    public static void main(String[] args) {
        /*4.new对应的是线程的新建状态
        * 5.要想模拟单线程,至少要启动两个线程,如果只启动一个,是单线程程序*/
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        MyThread t4 = new MyThread();
        /*6.这个run()如果直接调用,是没有多线程抢占执行的效果的
        * 只是业务方法看作是普通方法来调用,谁先写就先执行谁
        *
        * 7.start()对应的状态才是线程的就绪状态,它会把刚刚新建好的线程加入到就绪队列中,
        * 至于什么时候执行,就是多线程抢占的效果,需要OS选中分配时间片才会执行
        *
        * 8.执行start()时,底层会自动调用我们重写的业务方法run()
        *
        * 9.线程执行具有随机性,也就说t1-t4具体怎么执行
        * 取决于CPU调度时间片的分配规则,我们是决定不了的*/
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

class MyThread extends Thread {
    /*1.多线程编程实现的方案1:通过继承Thread类,并重写run()来完成*/
    //重写run(),run()里是我们自己的业务
    @Override
    public void run() {
        /*2.super.run()表示这里调用的是父类的业务,但是我们想用自己的业务,所以注释掉*/
        //super.run();
        //完成业务,打印10次当前正在执行的线程名称
        for (int i = 0; i < 10; i++) {
            /*3.getName()表示可以获取当前正在执行的线程名称,
             * 由于本类继承了Thread类,所以可以直接使用Thread类提供的功能*/
            System.out.println(i + "=" + getName());
        }
    }
}

多线程编程方案1:继承Thread
1.自定义自己的多线程类
2.重写run(),里面是我们自己的业务
3.创建自定义线程类对象
4.通过线程对象.start(),将线程加入就绪队列
5.查看多线程编程的抢占效果

本类用于多线程编程实现方案2:实现Runnable接口的方式

public class TestThread2 {
    public static void main(String[] args) {
        //4.创建自定义类的对象--目标业务类对象
        MyRunnable target = new MyRunnable();
        //5.没有start(),需要与Thread类建立关系
        Thread t1 = new Thread(target);//利用的是Thread的构造方法Thread(Runnable target)
        Thread t2 = new Thread(target);
        Thread t3 = new Thread(target);
        Thread t4 = new Thread(target);
        //6.一多线程的方式运行多个线程
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

//1.自定义多线程类
class MyRunnable implements Runnable {
    //2.添加父接口中为实现的抽象方法run(),里面是自己的业务
    @Override
    public void run() {
        //3.打印10次当前正在执行的线程名称
        for (int i = 0; i < 10; i++) {
            /*问题:自定义类与父接口Runnable中都没有获取线程名字的方法
             * 所以还需要从之前的Thread线程类中找思路:
             * currentThread():先通过这个静态方法,获取当前正在执行的线程对象
             * getName():然后获取线程对象的名字*/
            System.out.println(i + "=" + Thread.currentThread().getName());
        }
    }
}

多线程编程实现方案2:实现Runnable
1.自定义自己的多线程类
2.实现run(),里面是我们自己的业务
3.创建自定义对象,作为唯一的业务对象
4.创建多个Thread类对象,作为多线程对象,并将业务对象target传入
5.使用多个线程对象调用start()启动

我们如何判断程序中有没有可能出现线程安全问题,主要有以下三个条件:

在多线程中+有共享数据+多条语句操作共享数据
多线程的场景和共享数据的条件是改变不了的(就像4个窗口一起卖100张票,这个是业务),所以思路可以从第三点"多条语句操作共享数据"入手,既然是在这多条语句操作数据过程中出现了问题那我们可以把有可能出现问题的代码都包裹起来一次只让一个线程来执行
同步与异步
同步:好处是体现了排队效果,同一时刻只有一个线程独占资源,其他没有权利的线程排队,坏处是效率会降低,不过保证了安全
异步:体现了多线程抢占资源的效果,线程之间互相不等待,互相抢占资源
坏处是有安全隐患,效率高

  • 保证安全的前提下,提高程序的性能

同步使用的前提
1.同步需要两个或两个以上的线程(单线程无需考虑多线程安全问题)
2.多个线程必须使用同一个锁(我上锁后其他人也能看到这个锁,不然我的锁锁不住其他人,就没有了上锁的效果)

卖票超卖复卖加锁修改案例

public class TestRunnable1 {
    public static void main(String[] args) {
        //5.创建1个自定义类对象作为目标业务类型对象
        TicketRunnable target = new TicketRunnable();
        //6.创建多个线程对象,并且把业务交给线程对象
        Thread t1 = new Thread(target);
        Thread t2 = new Thread(target);
        Thread t3 = new Thread(target);
        Thread t4 = new Thread(target);
        //7.以多线程的方式启动
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
/*1.多线程中出现数据安全问题的原因:多线程程序+有共享数据+多条语句操作共享数据
 * 2.同步锁:相当于给容易出现问题的代码加了一把锁,包裹了所有可能会出现安全问题的代码
 * 加锁之后,就有了同步(排队)的效果,但是枷锁需要考虑枷锁的范围:
 * 不能太大,太大干啥都排队效率低,也不能太小,太小锁不住,还是有安全隐患*/

//1.定义自己的多线程类,实现接口
class TicketRunnable implements Runnable {
    //3.定义变量用来保存票数
    //8.如果采用的是实现接口的方式,接口实现类作为业务类只new了一次
    //所以票数只有一份,不需要设置成静态
    int tickets = 100;
    Object o = new Object();

    //2.添加父接口中未实现的抽象方法,里面是自己的业务
    @Override
    public void run() {
        //4.循环卖票
        while (true) {
            /*3.同步代码块:synchronized(唯一的锁对象){会出现安全隐患的代码}
             * 同步代码块可以保证在同一时刻,同一个资源只会被一个线程独享*/
            //synchronized (new Object()){//每一次来一个新线程,都会new一把新锁,不唯一,不行
            // synchronized (o){//这样锁得类型是Object,只有一把锁可以锁住
            synchronized (TicketRunnable.class) {//只要锁对象唯一,就可以
                //9.添加休眠,让每一个进入售票的进程休眠10ms,注意try-catch
                if (tickets > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //打印当前正在售票的线程名并且票数--
                    System.out.println(Thread.currentThread().getName() + "=" + tickets--);

                }
                //判断是否还有票,没票结束循环
                if (tickets <= 0) break;
            }
        }
    }
}

你可能感兴趣的:(java,intellij-idea,java-ee)