1.定义:

线程是进程的一个单元(进程就是启动一个应用程序)

2.实现方式:

继承Thread类:

  public class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(name+":"+"下载了"+i+"%");
        }
    }
  }
  ==================================================
  public class Test {
    public static void main(String[] args) {
        MyThread mt = new MyThread("海王");
        mt.start();

        MyThread mt1 = new MyThread("荔湾");
        mt1.start();
    }
  }

使用Runnable接口:

  public class DownloadMovies implements Runnable {
    private String name;

    public DownloadMovies(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(name+":"+"下载了"+i+"%");
        }
    }
  }
  ===================================================
  public class Test {
    public static void main(String[] args) {
        DownloadMovies dm = new DownloadMovies("小鬼当家");
        new Thread(dm).start();

        DownloadMovies dm1 = new DownloadMovies("家有儿女");
        new Thread(dm1).start();

        Thread t = new Thread(new DownloadMovies("海王"));
        t.start();
    }
  }

3.线程的生命周期

  • 新建:线程被new出来
  • 准备就绪:线程具有执行的资格,即线程调用了start(),没有执行的权力
  • 运行:具备执行的资格,具备执行的权力
  • 阻塞:没有执行的资格和执行的权力
  • 销毁:线程对象变成垃圾,释放资源(sleep(),wait())

4.线程的并发(安全问题)

实例:车票4个窗口售卖100张票,100张票是共享资源,4个窗口是4个线程同时工作.
解决:加锁synchroized()

格式:synchroized(加锁对象)
{
//操作共享资源的代码
}
同步代码加在什么地方?
a.代码被多个线程访问
b.代码中有共享的数据
c.共享数据被多条语句操作
例:

  public class SaleTicket extends Thread {
    private String name;
    static int ticket = 100;

    public SaleTicket(String name) {
        this.name = name;
    }
    //创建一个锁对象,这个对象是多线程对象所共享的数据
    static Object obj = new Object();
    @Override
    public void run() {
        while (true) {
        synchronized (obj)
        {
                if (ticket > 0) {
                    System.out.println(name + ":卖出的座位是:" + (ticket--) + "号");
                } else {
                    break;
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println(name+"卖票结束!");
    }
  }
  ====================================================
  public class TestTicket {
    public static void main(String[] args) {
        SaleTicket sa = new SaleTicket("窗口1");
        sa.start();

        SaleTicket sa1 = new SaleTicket("窗口2");
        sa1.start();

        SaleTicket sa2 = new SaleTicket("窗口3");
        sa2.start();

        SaleTicket sa3 = new SaleTicket("窗口4");
        sa3.start();
    }
  }

同步方法:

  public class SaleTicket extends Thread {
    private String name;
    static int ticket = 100;

    public SaleTicket(String name) {
        this.name = name;
    }

    static Object obj = new Object();
    @Override
    public void run() {
        while (true) {
                if (saleTicket()) {
                    break;
                }
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        System.out.println(name+"没票啦!");
        }


    public synchronized boolean saleTicket(){
        boolean isFinish = false;
        if (ticket > 0) {
            System.out.println(name + ":卖出的座位是:" + (ticket--) + "号");
                } else {
            isFinish = true;
                }
        return isFinish;
    }
  }

静态同步方法:锁对象不能是this,是本类的class文件

Lock锁:实现了synchronized方法和语句获得更广泛的锁定操作
方法:
void lock() 获取锁
void unlock() 释放锁
使用步骤:
在成员位置创建一个Reentrantlock对象
在可能出现的安全问题的代码前调用Lock接口中的方法Lock获取锁
在可能出现的安全问题的代码后调用Lock接口中的方法unlock释放锁
例:

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    public class SaleTicket extends Thread { 
    private String name;

    Lock lock = new ReentrantLock();
    static int ticket = 100;

    public SaleTicket(String name) {
        this.name = name;
    }

    static Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            lock.lock();
            if (ticket > 0) {
                System.out.println(name + ":卖出的座位是:" + (ticket--) + "号");

            } else {
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        System.out.println(name + "没票啦!");
    }

  }
  ================================================
  public class TestTicket {
    public static void main(String[] args) {
        SaleTicket sa = new SaleTicket("窗口1");
        sa.start();

        SaleTicket sa1 = new SaleTicket("窗口2");
        sa1.start();

        SaleTicket sa2 = new SaleTicket("窗口3");
        sa2.start();

        SaleTicket sa3 = new SaleTicket("窗口4");
        sa3.start();
    }
  }

5.休眠

在做服务端的程序的时候都需要给一个休眠时间,在synchronized代码块中不会释放cpu,会一直占用cpu的资源.

6.线程间通信(等待与唤醒机制,有效利用资源)

多个线程在处理同一个任务,但是处理的动作(线程的任务)却不相同.

  wait();        休眠线程
  notify();      唤醒等待队列中休眠的线程
  notifyAll();   唤醒等待队列的休眠的所有线程

7.线程池(容器)

Executors:线程池的工厂类,用来生成线程池
Executors类中的静态方法:
static ExecutorService newFiedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池
参数:int nThreads:创建线程池中包含的线程数量
返回值:ExecutorService接口,返回的是ExecutorService接口的实现类对象
submit(Runnable)
用来从线程池中获取线程,调用start方法,执行线程任务
void shutdown()
关闭销毁线程池的方法

线程池的使用步骤:

  • a.使用线程池工厂类Executors方法生产一个线程池
  • b.创建一个类,实现Runnable接口,重写run方法
  • c.调用ExecutorSevic接口的submit方法,开启线程,执行run方法
  • d.调用shutdown方法销毁关闭线程

例:

  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;

  public class ThreadPool {  
    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        es.submit(new RunnableImpl());
        es.submit(new RunnableImpl());
        es.submit(new RunnableImpl());
    }
  }  
  ===========================================================
  public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"创建了一个新的线程执行");
    }
  }

8.Lambda表达式(函数式编程简化代码)

使用前提:必须有接口且接口中有且只有一个抽象方法.必须具有上下文推断(方法的参数或局部变量必须为Lambda对应的接口类型)
标准格式:

  • a.一些参数
  • b.一个箭头
  • c.一段代码
  • (参数列表) -> {一些重写的方法代码}
  • ():接口中抽象方法的参数列表,没有参数就空着,多个参数逗号分隔
  • ->:把参数传递给方法体
  • {}:重写的方法代码

例:

  public class DemoCook {
    public static void main(String[] args) {
        //匿名内部类
        invokeCook(new Cook() {
            @Override
            public void makeFood() {
                System.out.println("吃饭了");
            }
        });
        //Lambda表达式
        invokeCook(()->{
            System.out.println("吃饭了!");
        });
    }
    private static void invokeCook (Cook cook)
    {
        cook.makeFood();
    }
  }
  ============================================
  public interface Cook {
    public abstract void makeFood();
  }
Last modification:May 29th, 2020 at 01:47 pm
如果觉得我的文章对你有用,请随意赞赏