多线程

(一)、进程、线程、多进程的概念
进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
线程:就是进程中的一个独立的控制单元。线程在控制着进程的执行。
注意点:
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();
      }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值