多线程

来源:互联网 发布:爱名网备案域名 编辑:程序博客网 时间:2024/04/29 02:30

(一)、进程、线程、多进程的概念
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。
注意点:
1、一个进程中至少有一个线程。
2、一个进程中可以有多个执行路径,称之为多线程。
3、开启多个线程是为了同时运行多部分代码,每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务。

多线程的好处:解决了多部分代码同时运行的问题。
多线程的弊端:线程太多,会导致效率的降低。

什么是”并行”和”并发”:
1.”并行”是指逻辑上一起在执行,它强调的是在”同一段时间内”一起运行的程序;
2.”并发”是指物理上的抢占同一资源。它强调的是在”同一时刻时”一起抢占系统的某个共享资源;

(二)、线程的创建方式
创建线程方式一:继承Thread类
1. 定义一个类继承Thread类。
2. 覆盖Thread类中的run方法。
3. 直接创建Thread的子类对象创建线程。
4. 调用start方法开启线程并调用线程的任务run方法执行。

class Test extends Thread{    private String name;    public Test(String name)    {        this.name=name;    }    public void run()    {        for (int x=0;x<100 ;x++ )        {            System.out.println((Thread.currentThread()==this)+"----"+this.getName()+"run----"+x);        }    }}class ThreadTest{    public static void main(String[] args)    {        Test t1=new Test("xiaomi");        Test t2=new Test("liming");        t1.start();        t2.start();        for(int x=0;x<100;x++)        {            System.out.println("main------"+x);        }    }}

创建线程方式二:实现Runnable接口
1. 定义类实现Runnable接口。
2. 覆盖接口中的run方法,将线程的任务代码封装到run方法中。
3. 通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中。所以要在线程对象创建时就必须明确要运行的任务。
4. 调用线程对象的start方法开启线程。

实现Runnable接口的好处:
1. 将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务封装成对象。
2. 避免了Java单继承的局限性。所以,创建线程的第二种方式较为常用。

class Demo implements Runnable{      public void run(){            show();      }      public void show(){             for(int x = 0; x < 100; 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();       }}

(三)、线程安全问题
线程安全问题产生的原因?
1. 多个线程在操作共享的数据。
2. 操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
线程安全问题的解决方案?
将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
格式有两种:
synchronized(对象){
需要被同步的代码;
}
在函数上加上synchronized修饰符
很好的解决了线程安全问题,但是同步的弊端是当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。
需求:储户,两个,每个都到银行存钱,每次存100,共存三次。

class Bank{       private int sum ;       public void add(int num){             synchronized(this ){                  sum = sum + num;                  System. out.println("sum = " + sum);            }      }}class Cus implements Runnable{       private Bank b = new Bank();       public void run(){             for(int x = 0; x < 3; x++){                   b.add(100);            }      }}class BankDemo{       public static void main(String[] args){            Cus c = new Cus();            Thread t1 = new Thread(c);            Thread t2 = new Thread(c);            t1.start();            t2.start();      }}

(四)、多线程下的单例设计模式
饿汉式

class Single{    private static final Single s=new Single();    private Single(){}    public static Single getInstance()    {        return s;    }}

懒汉式

class Single{    private static Single s=null;    private Single(){}    public static Single getInstance()    {        if(s==null)        {            synchronized(Single.class)            {                if(s==null)                    //---->A                    s=new Single();            }        }        return s;    }}

比较:饿汉式不存在安全问题,因为不存在多个线程共同操作数据的情况,懒汉式存在安全问题,可以使用同步函数解决, 但若直接使用同步函数,则效率较低,因为每次都需要判断,需要提前判断以提高效率。
(五)、线程间的通信–生产者和消费者
这里写图片描述
1. wait():让线程处于冻结状态,被wait的线程会被存储到线程池中。
2. notify():唤醒线程池中的一个线程(任何一个都有可能)。
3. notifyAll():唤醒线程池中的所有线程。
4、wait和sleep区别?
1)wait可以指定时间也可以不指定。sleep必须指定时间。
2)在同步中时,对CPU的执行权和锁的处理不同。
wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。

多生产着和多消费着问题

class Resource{       private String name ;       private int count = 1;       private boolean flag = false;       public synchronized void set(String name){            while(flag )                   try{                         this.wait();                  } catch(InterruptedException e){                        e.printStackTrace();                  }             this.name = name + count;             count++;             System.out.println(Thread.currentThread().getName() + "...生产者..." + this. name);             flag = true ;             notifyAll();      }       public synchronized void out(){             while(!flag )                   try{                         this.wait();                  } catch(InterruptedException e){                        e.printStackTrace();                  }            flag = false ;            notifyAll();            System.out.println(Thread.currentThread().getName() + "...消费者..." + this. name);      }}class Producer implements Runnable{       private Resource r ;      Producer(Resource r){             this.r = r;      }       public void run(){             while(true ){                   r.set( "馄饨");            }      }}class Consumer implements Runnable{       private Resource r ;      Consumer(Resource r){             this.r = r;      }       public void run(){             while(true ){                   r.out();            }      }}class ProducerConsumerDemo {       public static void main(String[] args){            Resource r = new Resource();            Producer pro = new Producer(r);            Consumer con = new Consumer(r);            Thread t0 = new Thread(pro);            Thread t1 = new Thread(pro);            Thread t2 = new Thread(con);            Thread t3 = new Thread(con);            t0.start();            t1.start();            t2.start();            t3.start();      }}
0 0