多线程学习..害慢慢写吧

多线程

  • 线程就是独立的执行路径;

  • 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程; .

  • main()称之为主线程,为系统的入口,用于执行整个程序;

  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为的干预的。

  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制;

  • 线程会带来额外的开销,如cpu调度时间,并发控制开销。

  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

 

 

 

三种创建方式

 

 

 

 

 

调用run()与start()

 

 

 

 

 

 

 

 

 

 //创建线程方式一:继承Thread类,重写Run方法,调用Start开启线程
 //总结:线程开启不一定立即执行,由cpu调度执行
 public class TestThread01 extends Thread{
     @Override
     public void run() {
         //run方法线程体
         for (int i = 0; i < 20; i++) {
             System.out.println("副线程0000000");
        }
    }
 
     public static void main(String[] args) {
         //创建一个线程对象
         TestThread01 thread1 = new TestThread01();
         //调用start()方法开启线程
         thread1.start();
         for (int i = 0; i < 2000; i++) {
             System.out.println("主线程"+i);
        }
    }
 }

 

 

多个线程同时操作一个资源

 

 //多个线程同时操作同一个对象
 //买火车票
 
 //发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱
 public class TestThread04 implements Runnable {
     //票数
     private int ticketNums = 10;
 
     @Override
     public void run() {
         while (true){
             if (ticketNums<=0){
                 break;
            }
             try {
                 Thread.sleep(200);
            } catch (InterruptedException e) {
                 e.printStackTrace();
            }
             System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--+"张票");
        }
    }
 
     public static void main(String[] args) {
         TestThread04 testThread04 = new TestThread04();
         new Thread(testThread04,"学生").start();
         new Thread(testThread04,"老师").start();
         new Thread(testThread04,"黄牛").start();
    }
 }

 

 

callable接口

 

 

 

 

 

静态代理

     //静态代理模式总结:
     //真实对象与代理对象都要实现同一个接口
     //代理对象要代理真实角色
 public class StaticProxy {
     public static void main(String[] args) {
         You you = new You();
         WeddingCompany weddingCompany = new WeddingCompany(you);
         weddingCompany.marry();
    }
 
 }
 
 class You implements Marry{
     @Override
     public void marry() {
         System.out.println("结婚");
    }
 }
 
 class WeddingCompany implements Marry{
     private Marry target;
 
     public WeddingCompany(Marry target) {
         this.target = target;
    }
 
     @Override
     public void marry() {
         before();
         this.target.marry(); //真实对象
         after();
    }
 
     private void before() {
         System.out.println("结婚前");
    }
 
     private void after() {
         System.out.println("结婚后");
    }
   
 }
 
 interface Marry{
     void marry();
 }

 

 

 

Lamda表达式

 

 

 

La mda表达式.

◆理解Functional Interface ( 函数式接口)是学习Java8 lambda表达式的关键所在。

◆函数式接口的定义:任何接口,如果只包含唯一 一 个抽象方法,那么它就是一个函数式接口。

◆对于函数式接口,我们可以通过lambda表达式来创建该接口的对象。

 public class TestLambda02 {
     public static void main(String[] args) {
         //简化1、参数类型
         ILove love = (a) -> {
             System.out.println("I love you!");
        };
         love.showLove(233);
         //简化2、简化括号
         love = a -> {
             System.out.println("I love you");
        };
         //简化3、去掉花括号
         love = a -> System.out.println("I love you");
         //总结:
               //lambda表达式只能有一行代码的情况下才能简化为一行,多行需用代码块包裹
               //前提是接口是函数式接口
               //多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号
    }
 }
 
 interface ILove{
     void showLove(int a);
 }
 
 class Love implements ILove{
     @Override
     public void showLove(int a) {
         System.out.println("I love you"+a);
    }
 }

 

 

线程状态

 

 

 

 

 

 

 

 

 

 

 

线程方法

 

 

 

停止线程

 

 

 

 

线程同步

◆由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中 被访问时的正确性,在访问时加入锁机制synchronized ,当一个线程获得对象的排它锁,独占资源,其他线程必须等待,使用后释放锁即可. 存在以下问题:

◆ 一个线程持有锁会导致其他所有需要此锁的线程挂起;

◆在多线程竞争下,加锁,释放锁会导致比较多的上下文切换和调度延时,引起性能问题;

◆如果一个优先级高的线程等待一 个优先级低的线程释放锁会导致优先级倒置,引起性能问题.

同步方法

 

 

 

方法里面需要修改的内容才需要锁,锁的太多,浪费资源

 

 

 

死锁

概念:

 

 

产生条件:

 

 

 

lock:

◆从JDK 5.0开始,Java提供了更强大的线程同步机制一通过 显式定义同步锁对象来实现同步。同步锁使用L ock对象充当

◆java.util.concurrent.locks.Lock接口是控制多个线程对共享 资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得L ock对象 ◆ReentrantLock 类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

 

 

 

synchronized与lock:

◆Lock是显式锁(手动开启和关闭锁,别忘记关闭锁) synchronized是隐式锁, 出了作用域自动释放

◆Lock只有代码块锁,synchronized有代码块锁和方法锁

◆使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

◆优先使用顺序: Lock >同步代码块(已经进入了方法体,分配了相应资源) >同步方法(在方法体之外)

 

 

生产者与消费者问题

 

 

 

解决线程通信方法

 

 

线程池

 

 

 //测试线程池
 public class TestPool {
 
     public static void main(String[] args) {
         //创建服务,创建线程池
         //newFixedThreadPool参数为线程池大小
         ExecutorService service = Executors.newFixedThreadPool(10);
         //执行
         service.execute(new MyThread());
         service.execute(new MyThread());
         service.execute(new MyThread());
         //关闭链接
         service.shutdown();
    }
 
 }
 
 
 class MyThread implements Runnable {
     @Override
     public void run() {
         System.out.println(Thread.currentThread().getName());
    }
 }

 

 

 

 

posted @ 2020-03-31 22:09  宸、  阅读(89)  评论(0)    收藏  举报