JAVA进阶(线程与进程)

一,进程与线程

  • 进程是资源分配的最小单位,线程是资源调度(程序执行)的最小单位
  • 进程指一次程序的完整运行,一个进程包含多个线程,线程比进程处理快,线程的存在离不开进程,一个线程终止整个进程将终止,而进程之间不会相互影响
  • 例如打开微信,就相当于启动一个进程,打开朋友圈,微信运动等相当于执行线程
  • 再例如,进程相当于火车,线程相当于车厢

二,多线程的实现方法

  • 实现多线程的两种方式:继承Thread类,继承Runnable接口
  • Thread 类start()方法用于启动多线程,自动调用run()方法(这是由jvm所决定的),run()地位相当于main(),都是程序的入口,run()是线程程序的入口,main()是主程序的入口。
  • 启动顺序并不等于执行顺序,先start()不一定先run()
  • Runnable接口 没有start()方法,但可以使用 public Thread(Runnable target){},调用该接口的子类对象
package 进程与线程;

class MyThread extends Thread{
    private String str;

    public MyThread(String str)
    {this.str=str;}

    //覆写Run方法
    @Override
    public void run() {
        for (int i = 0; i <200 ; i++) {
            System.out.println(this.str+"--->"+i);
        }
    }
}

public class ThreadDemo  {
    public static void main(String[] args) {
        MyThread m1 = new MyThread("线程1");
        MyThread m2 = new MyThread("线程2");
        MyThread m3 = new MyThread("线程3");
        m1.start();
        m2.start();
        m3.start();

    }
}

package 进程与线程;

class MyThread  implements Runnable{
    private String str;

    public MyThread(String str)
    {this.str=str;}

    //覆写Run方法
    @Override
    public void run() {
        for (int i = 0; i <200 ; i++) {
            System.out.println(this.str+"--->"+i);
        }
    }
}

public class ThreadDemo  {
    public static void main(String[] args) {
        MyThread m1 = new MyThread("线程1");
        MyThread m2 = new MyThread("线程2");
        MyThread m3 = new MyThread("线程3");

        new Thread(m1).start();
        new Thread(m2).start();
        new Thread(m3).start();
    }
}

  • Thread类是Runnable的子类,接口实现了多继承
    在这里插入图片描述

三,进程与线程的比较

  • 多个线程对象访问同一资源用Runnable接口,实现资源共享(车厢a换到车厢b),而进程之间很难实现资源共享
package 进程与线程;

class MyThread extends Thread{
    private int ticket = 10;
    //覆写Run方法
    @Override
    public void run() {

        for (int i = 0; i <50 ; i++) {
            if(ticket>0)
            System.out.println("剩余票数:"+"--->"+ticket--);
        }
    }
}

public class ThreadDemo  {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        MyThread m2 = new MyThread();
        MyThread m3 = new MyThread();
        m1.start();
        m2.start();
        m3.start();
    }
}

  • 实例化三个不同的线程对象,每个线程对象对各自的ticket进行操作,没有实现资源共享
    在这里插入图片描述

在这里插入图片描述

package 进程与线程;

class MyThread implements Runnable{
    private int ticket = 10;
    //覆写Run方法
    @Override
    public void run() {

        for (int i = 0; i <50 ; i++) {
            if(ticket>0)
            System.out.println("剩余票数:"+"--->"+ticket--);
        }
    }
}

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

  • 实例化三个Thread类进程对象,每个进程对象对应同一个MyThread子类对象,可以实现资源共享
    在这里插入图片描述
  • 关于ticket输出不是10,9,8,7,6,5,4,3,2,1,0,以为ticket不是原子操作,受到线程的影响,可能先println,再进行ticket- -,或者先进行ticket- -再进行println <可以这样理解,卖出票时要记下剩余票数并报出(println),许多票贩分布在大街小巷卖票a卖出了一张票(ticket - -),b卖出了一张票(ticket - -),这时b先当时记下报出剩余票数,a后报出当时记下的剩余票数>
    在这里插入图片描述
    四,多线程的同步问题:
    1.问题的引出:多个线程访问同一资源,例如多个票贩卖同一张票,票数出现负数的情况。
package 进程与线程;
class MyThread implements Runnable{
    private int ticket = 10;
    //覆写Run方法
    @Override
    public void run() {
        for (int i = 0; i <20 ; i++) {
            if(ticket>=0)
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            System.out.println(Thread.currentThread().getName()+"--->"+ticket--);
        }
    }
}
public class ThreadDemo  {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        new Thread(m1,"票贩子a").start();
        new Thread(m1,"票贩子b").start();
        new Thread(m1,"票贩子c").start();
    }
}

在这里插入图片描述
在这里插入图片描述

  • 第一个线程执行并休眠时,没有进行ticket - - ,当前票数仍为1,所以第二个线程执行时,通过了剩余票数的判断,最后进行修改剩余票数时,会出现负数的情况。

2.解决方法:使用synchronized(){},进行上锁,以下两种方法都是为了保证同一时间只有一个线程被执行,其他线程必须等待该线程执行完成才能执行,即同一时间只有一个票贩卖票。
在这里插入图片描述

  • 同步代码块
package 进程与线程;
class MyThread implements Runnable{
    private int ticket = 10;
    //覆写Run方法
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
            synchronized (this) {//当前操作只允许一个线程对象进入
                if (this.ticket >= 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "--->" + this.ticket--);
                }
            }
        }
    }
}
public class ThreadDemo  {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        new Thread(m1,"票贩子a").start();
        new Thread(m1,"票贩子b").start();
        new Thread(m1,"票贩子c").start();
    }
}

在这里插入图片描述

  • 同步函数
package 进程与线程;
class MyThread implements Runnable{
    private int ticket = 10;
    //覆写Run方法
    @Override
    public void run() {
        for (int i = 0; i <100 ; i++) {
           this.sale();
        }
    }
    public synchronized void sale()
    {
            if (this.ticket >= 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "--->" + this.ticket--);
            }
    }

}
public class ThreadDemo  {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        new Thread(m1,"票贩子a").start();
        new Thread(m1,"票贩子b").start();
        new Thread(m1,"票贩子c").start();
    }
}

在这里插入图片描述
在这里插入图片描述

  • 将判断剩余票数,休眠,修改剩余票数用synchronized进行封装上锁,使得同一时间只能有一个线程对象执行这个完整操作
  • 同步操作与异步操作相比,执行速度低于异步操作,但同步操作的安全性高。

五,多线程经典模型-----生产者与消费者:生产一个,取走一个进行输出,不存在连续重复输出同一个产品,而且产品的特点不会产生错乱的情况,实现了线程有序交替执行。
在这里插入图片描述

package 进程与线程;
class Info
{
    private String title;
    private String content;
    private boolean flag  = true;
    //flag=true,可以生产不可以取走,flag=flase 可以取走不可以生产
    public synchronized void set(String title,String content) throws InterruptedException {
        if(this.flag==false)//重复进入set(),发现不可以生产,进行等待
        {
            super.wait();
        }
        this.title=title;
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.content=content;
        this.flag=false;//生产完后进行标记修改
        super.notify();//唤醒其他等待取出数据线程
    }
    public synchronized void get() throws InterruptedException {
        if(flag==true)//重复进入get(),数据正在生产中,发现取不到数据,进行等待
        {
            super.wait();
        }
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.title+"---->"+this.content);
        this.flag=true;//取走数据,进行标记的修改
        super.notify();//唤醒其他等待生产数据线程
    }
}
class Productor implements Runnable{
    private Info info;
    public Productor(Info info)
    {this.info=info;}

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if(i%2==0) {
                try {
                    this.info.set("生产油桃", "饱满多汁");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        else {
                try {
                    this.info.set("生产哈密瓜","香甜可口");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
class Customer implements Runnable {
    private Info info;

    public Customer(Info info) {
        this.info = info;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            try {
                this.info.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
    public class ThreadDemo1 {
        public static void main(String[] args) {
            Info info = new Info();
            new Thread(new Productor(info)).start();
            new Thread(new Customer(info)).start();
        }
}

在这里插入图片描述

  • sleep()与wait()区别,sleep()是Thread类定义的方法,wait()是Object类定义的方法
    sleep()可以设置休眠时间,时间一到自动唤醒,wait()休眠需要notify()进行唤醒
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值