016_多线程

Posted lydbky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了016_多线程相关的知识,希望对你有一定的参考价值。

1.进程和线程

  进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。(进程是资源分配的最小单位)

  线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)

 

2.线程的生命周期及五种基本状态

  技术分享图片

  (1)新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

  (2)就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线      程立即就会执行;

  (3)运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态                执行,首先必须处于就绪状态中;

  (4)阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻              塞产生的原因不同,阻塞状态又可以分为三种:

    ①等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

    ②同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

    ③其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

  (5)死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

 

3.线程的创建方式

  (1)继承Thread类

    ①定义一个类继承Thread类
    ②覆盖Thread类中的方法
    ③直接创建Thread的子类对象创建线程
    ④调用start方法开启线程并调用线程的任务run方法执行

class Demo extends Thread
{
    private String name;
    
    Demo(String name)
    {
        this.name=name;
    }
    
    public void run()
    {
        for(int i=0;i<10;i++)
        {
            System.out.println("i="+i+" name="+Thread.currentThread().getName());
        }
    }
}

class ThreadDemo
{
    public static void main(String[] args)
    {
        Demo demo1=new Demo("С?");
        Demo demo2=new Demo("κ?");
        
        demo1.start();
        demo2.start();
        
        for(int i=0;i<10;i++)
        {
            System.out.println("i="+i+" name="+Thread.currentThread().getName());
        }
        
    }
}

  (2)实现Runnable接口

    ①定义类实现Runnable接口。

    ②覆盖接口种的run方法,将线程的任务代码封装到run方法中。
    ③通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造参数进行传递。
    ④调用线程对象的start方法开启线程。

class Demo implements Runnable
{
    public void run()
    {
        show();
    }
    public void show()
    {
        for(int x=0; x<20; x++)
        {
            System.out.println(Thread.currentThread().getName()+"....."+x);
        }
    }
}


class  ThreadDemo
{
    public static void main(String[] args) 
    {    
        Demo d = new Demo();
        Thread t1 = new Thread(d);
        Thread t2 = new Thread(d);
        t1.start();
        t2.start();
    }
}

 

4.线程的安全问题(同步)

  (1)同步代码块   

    synchronized(对象)
    {
      需要被同步的代码;
    }

class Ticket implements Runnable
{
    private int num=100;
    private Object obj=new Object();
    
    public void run()
    {
        while(true)
        {
            synchronized(obj)
            {
                if(num>0)
                {
                    try{Thread.sleep(10);}catch(InterruptedException e){}
                    System.out.println(Thread.currentThread().getName()+"...sale..."+num--);
                }
            }

        }
    }
}

class TicketDemo
{
    public static void main(String[] args)
    {
        Ticket t=new Ticket();
        
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        
        t1.start();
        t2.start();
    }
}

  (2)同步函数

    使用synchronized关键字

class Bank
{
    private static int sum=0;
    
    public synchronized void add(int num)
    {
        sum+=num;
        try{Thread.sleep(10);}catch(InterruptedException e){}
        System.out.println("sum="+sum);
    }
}

class Customer implements Runnable
{
    private Bank b=new Bank();
    
    public void run()
    {
        for(int i=1;i<=3;i++)
        {
            b.add(100);
        }
    }
}

class BankDemo
{
    public static void main(String[] args)
    {
        Customer c=new Customer();
        
        Thread t1=new Thread(c);
        Thread t2=new Thread(c);
        
        t1.start();
        t2.start();
    }
}

  (3)同步代码块和同步函数的区别

    ①同步函数的使用的锁是this,同步代码块的锁是任意的对象,建议使用同步代码块

    ②静态的同步函数使用的锁是该函数所属的字节码文件对象,可以用getClass方法获取,也可以用当前类名.class表示


5.线程间的通信

   (1)等待唤醒机制

    ①wait():让线程处于冻结状态,被wait的线程会被存储到线程池中
    ②notify():唤醒线程池中的一个线程(任意)
    ③notifyAll():唤醒线程池中的所有线程

    注意:这些方法都必须定义在同步中,必须要明确到底操作的是哪个锁上的线程。

         锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中

  












以上是关于016_多线程的主要内容,如果未能解决你的问题,请参考以下文章

多线程 Thread 线程同步 synchronized

016 原子类

我奶奶都能看懂系列016Python进程和线程的使用

多个用户访问同一段代码

016_go语言中的递归

线程学习知识点总结