黑马程序员——java基础——多线程

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

进程:是一个正在执行中的程序。
每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。

线程:就是进程中的一个独立的控制单元。
线程在控制着进程的执行。

创建线程的方法一:
1.继承Thread类
2.复写Thread类中的run方法
目的是将自定义的代码存储到run方法中,可以让线程执行
3.调用start方法
目的是开启线程,调用run方法

创建线程的方法二:
1.实现Runnable接口
2.复写Runnable接口中的run方法
3.建立Runnable接口的子类对象
4.将Runnable接口的子类对象作为参数传递给Thread类的构造函数
Runnable接口本身并不能创建线程,所以其子类对象并不能调用Thread类中的start方法,即不能开启线程,所以要将其子类对象传递给Thread类,这样才能让线程去运行Runnable接口子类中的run方法
5.调用Thread类中start方法启动线程并运行Runnable接口子类中的run方法

继承Thread类和实现Runnable接口的区别:
实现接口解决了只能单继承的局限性,建议实现接口

区别:
继承Thread类:线程代码存放在Thread类的子类run方法中。
实现Runnable接口:线程代码存放在接口的子类run方法中。

class Demo extends Thread
{
    public void run()
    {
        for (int x = 0;x<50 ;x++ )
        {
            System.out.println("Demo run......"+x);
        }
    }
}

class ThreadDemo 
{
    public static void main(String[] args) 
    {
        Demo d = new Demo();//创建了一个线程
        d.start();//开启线程,并执行线程中的run方法
        d.run();//只是简单的对象调用方法,没有开启线程
    }
}

多线程中常见的安全问题,我们需要通过加锁来解决。

Java对于多线程的安全问题提供了专业的解决方式。
就是同步代码块。
synchronized(对象)
{
需要被同步的代码
}
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。

对象如同锁。持有锁的线程可以在同步中执行。
没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁

怎样在代码中解决安全问题:
1.找到多线程所运行的代码 (run方法中所用到的代码)
2.找到共享数据 (几个线程都需要使用的数据)
3.找到操作共享数据的代码,并将其同步

同步函数所使用的锁是 this(函数要被对象所使用,对象有所属的引用就是this)
静态同步函数所使用的锁是该方法所在类的字节码文件对象,即 类名.class

加锁的利弊:
好处:解决了多线程的安全问题。
弊端:多个线程需要判断锁,较为消耗资源,

//1000张票四个售票员同时卖
class Ticket implements Runnable//extends Thread
{
    //private static int x =1000;
    private int x = 1000;
    Object obj = new Object();
    public void run()
    {
        while(true)
        {   
            //加锁解决安全问题,一定要先确定需要同步的代码
            synchronized(obj)
            {
                if (x>0)
                {
                    try
                    {
                        Thread.sleep(10);
                    }
                    catch (Exception e)
                    {
                    }
                    System.out.println(Thread.currentThread().getName()+"......."+x--);
                }
            }
        }
    }
}

class TicketTest
{
    public static void main(String[] args) 
    {
        /*
        Ticket t1 = new Ticket();
        Ticket t2 = new Ticket();
        Ticket t3 = new Ticket();
        Ticket t4 = new Ticket();

        //开启的四个线程,他们有各自的资源,资源并不共享,可以通过加static的形式让资源共享
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        */

        Ticket t = new Ticket();
        //传入的是同一个对象,所以资源共享
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        Thread t4 = new Thread(t);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

线程间的相互通信:
其实就是多个线程在操作同一个资源,但是操作的动作不同。

例:
生产者消费者,生产一个消费一个并存在多个生产者和消费者

思路:
1.定义一个资源,它既具有生产的方法同时具有消费的方法
2.定义一个生产者实现Runnable接口,同时在run函数中调用资源中的生产方法
3.定义一个消费者实现Runnable接口,在run函数中调用资源中的消费方法
4.开启并运行生产和消费的线程

要想让生产者和消费者有关系并且生产一个就消费一个,可以通过标记和等待唤醒机制来完成

class Resource
{
    private String name;
    private int count = 1;
    private boolean flag = false;
    public synchronized void produce(String name)
    {
        while (flag)
        {
            try
            {
                //如果标记为true,就会等待
                this.wait();
            }
            catch (Exception e)
            {
            }
        }
        this.name = name+"..."+count++;
        System.out.println(Thread.currentThread().getName()+"..生产者.."+this.name);
        //生产一个商品后,就将标记改为true,这样生产者就会等待,然后唤醒所有的线程
        flag = true;
        this.notifyAll();
    }
    public synchronized void consume()
    {
        while (!flag)
        {
            try
            {
                //如果标记为false就会等待
                this.wait();
            }
            catch (Exception e)
            {
            }
        }
        System.out.println(Thread.currentThread().getName()+"...消费者..."+this.name);
        //消费完后,改变标记,唤醒所有线程
        flag = false;
        this.notifyAll();
    }
}

class Producer implements Runnable
{
    Resource res ;
    Producer(Resource res)
    {
        this.res = res ;
    }
    public void run()
    {
        while (true)
        {
            res.produce("旺旺");
        }       
    }
}
class Consumer implements Runnable 
{
    Resource res ;
    Consumer(Resource res)
    {
        this.res = res ;
    }
    public void run()
    {
        while (true)
        {
            res.consume();
        }       
    }
}
class ProducerConsumerDemo
{
    public static void main(String[] args)
    {
        //同一个对象资源共享 
        Resource res = new Resource();
        /*
        Producer pro = new Producer(res);
        Consumer con = new Consumer(res);

        Thread t1 = new Thread(pro);
        Thread t2 = new Thread(pro);
        Thread t3 = new Thread(con);
        Thread t4 = new Thread(con);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        */

        //创建并开启四个线程,两个为生产者,两个为消费者
        new Thread(new Producer(res)).start();
        new Thread(new Producer(res)).start();
        new Thread(new Consumer(res)).start();
        new Thread(new Consumer(res)).start();

    }
}

停止线程:
特殊情况:当线程处于冻结状态,就不会读到标记,那么线程就不会结束
为了让线程结束,Thread类提供了一个interrupt方法,可以强制让线程从冻结中醒来,但会报出一个InterruptedException

class Interrupte implements Runnable 
{
    //定义一个标记
    boolean flag = true ;
    public synchronized void run ()
    {
        while (flag)
        {
            try
            {
                wait();
            }
            //如果能够捕捉到异常,说明线程被强制打断,这时在异常处理时只要改变标记就可让程序停止
            catch (InterruptedException e)
            {
                System.out.println(Thread.currentThread().getName()+"....Exception");
                flag = false;
            }
            System.out.println(Thread.currentThread().getName()+"....run");
        }
    }
}

class InterrupteDemo 
{
    public static void main(String[] args) 
    {
        Interrupte in  = new Interrupte();

        Thread t1 = new Thread(in);
        Thread t2 = new Thread(in);
        t1.start();
        t2.start();

        int x = 0 ;
        while (true)
        {
            if (x++ == 50)
            {
                t1.interrupt();//强制打断t1进程
                t2.interrupt();//强制打断t1进程
                break;
            }
            System.out.println("main....run......"+x);
        }
    }
}

守护线程:
void setDaemon(boolean on)
当传入的值为true时,为守护线程,当前台线程都结束时,守护线程也结束,线程jvm退出。
在启动线程前调用,主线程结束,守护线程结束。

多线程的join方法
void join()
当A线程执行到了B线程的.join()方法时,A就会等待。等B线程都执行完,A才会执行。
join可以用来临时加入让指定线程执行。

多线程的setPriority方法
void setPriority(int newPriority)
用于更改线程的优先级。

多线程的yield方法
static void yield()
暂停当前正在执行的线程对象,并执行其他线程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值