Java基础学习笔记4

多线程的引入

         线程:线程是程序执行的一条路径, 一个进程中可以包含多条线程;多线程并发                 执行可以提高程序的效率, 可以同时完成多项工作

         多线程的应用场景

              红蜘蛛同时共享屏幕给多个电脑

              迅雷开启多条线程一起下载

              QQ同时和多个人一起视频

              服务器同时处理多个客户端请求

多线程并行和并发的区别

         ·并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需              要多核CPU)

         ·并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安        排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。

         ·比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙        聊天,这就叫并行。

         ·如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再        跟乙聊。这就叫并发。

Java程序运行原理和JVM的启动是多线程的吗

         Java程序运行原理:Java命令会启动java虚拟机,启动JVM,等于启动了一个                    应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后          主线程去调用某个类的 main 方法。

         JVM的启动是多线程的吗:JVM启动至少启动了垃圾回收线程和主线程,所以是多            线程的。

多线程程序实现的方式1

         继承Thread:

                     定义类继承Thread

                     重写run方法

                     把新线程要做的事写在run方法中

                     创建线程对象

                     开启新线程, 内部会自动执行run方法

        

       public class ThreadDemo {

 

   public static void main(String[] args) {

      //4,创建自定义类的对象

      MyThreadmt = new MyThread();

      //5,开启线程

      mt.start();

      //主线程和子线程会交替执行

      for(int i=0;i<1000;i++){

         System.out.println("bb");

      }

   }

}

//1,定义类继承Thread

class MyThread extends Thread{

   //2,重写run方法

   @Override

   public void run() {

      //3,将要执行的代码,写在run方法中

      for(int i=0;i<1000;i++){

         System.out.println("aaaaaaaaa");

      }

   }

}

 

多线程程序实现的方式2

         实现Runnable

                     定义类实现Runnable接口

                     实现run方法

                     把新线程要做的事写在run方法中

                     创建自定义的Runnable的子类对象

                     创建Thread对象, 传入Runnable

                     调用start()开启新线程, 内部会自动调用Runnable的run()方法

public class ThreadDemo1 {

   public static void main(String[] args) {

      //4,创建自定义对象

      MyRunnablemr = new MyRunnable();

      //5,将其当作参数传递给Thread的构造函数

      Threadt = new Thread(mr);

      //6,开启线程

      t.start();

     

      for(int i = 0; i < 1000; i++) {

         System.out.println("bb");

      }

   }

}

//1,定义一个类实现Runnable接口

class MyRunnable implements Runnable{

   //2,重写run方法

   @Override

   public void run() {

      //3,将要执行的代码写在run方法中

      for(int i=0;i<1000;i++){

         System.out.println("aaaaaaaaa");

      }

   }

}

实现Runnable的原理

         1,看Thread类的构造函数,传递了Runnable接口的引用

         2,通过init()方法找到传递的target给成员变量的target赋值

         3,查看run方法,发现run方法中有判断,如果target不为null就会调用                   Runnable接口子类对象的run方法

多线程两种方式的区别

         查看源码的区别:

              a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时,                   直接找子类的run()方法

              b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了                  它, start()调用run()方法时内部判断成员变量Runnable的引用是否               为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的                   run()方法

         继承Thread

              好处是:可以直接使用Thread类中的方法,代码简单

              弊端是:如果已经有了父类,就不能用这种方法

         实现Runnable接口

              好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现                    接口,而且接口是可以多实现的

              弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到                Thread的方法,代码复杂

匿名内部类实现线程的两种方式

       继承Thread类

              //1,new (){}继承这个类

      new Thread() {

         //2,重写run方法

         public void run() { 

            //3,将要执行的代码,写在run方法中

            for(int i = 0; i < 3000; i++) {

                System.out.println("aaaaa");

            }

         }

      }.start();//4,开启线程

 

       实现Runnable接口

              //1,new 接口(){}实现这个接口

      new Thread(new Runnable(){

         //2,重写run方法

         public void run() {

            //3,将要执行的代码,写在run方法中

            for(int i = 0; i < 3000; i++) {

                System.out.println("bb");

            }

         }

      }).start();//4,开启线程

线程获取名字和设置名字

         获取名字:通过getName()方法获取线程对象的名字

         设置名字:通过构造函数可以传入String类型的名字

         设置名字方法一:

      new Thread("xxx") {// 通过构造法方法给线程设置名字

         public void run() {

            for (int i = 0; i < 1000; i++) {

                // 匿名内部类调用

   // 通过getName方法获取线程名字

   System.out.println(this.getName() + "....aaaaa");

            }

         }

      }.start();

    设置名字方法二:

      new Thread() {

         public void run() {

            // 通过setName方法设置线程名字

            this.setName("yyy");

            for (int i = 0; i < 1000; i++) {

   // 通过getName方法获取线程名字

   System.out.println(this.getName() + "....bb");

            }

         }

      }.start();

    设置名字方法三:

      Threadt = new Thread() {

         public void run() {

            for (int i = 0; i < 1000; i++) {

      // 通过getName方法获取线程名字

      System.out.println(this.getName() + "....bb");

            }

         }

      };

      // 通过setName方法设置线程名字

      t.setName("zzz");

      t.start();

获取当前线程的对象

       new Thread(){

         public void run() {

            for(int i = 0; i < 1000; i++) {

                //获取当前线程对对象

   System.out.println(Thread.currentThread().

         getName()+ "...aaaaaaaaa");

            }

         }

      }.start();

       new Thread(new Runnable() {

         public void run() {

            for(int i = 0; i < 1000; i++) {

                //获取当前线程对象                  System.out.println(Thread.currentThread().

      getName()+ "...bb");

            }

         }

      }).start();

      //获取主函数线程的引用,并改名字

      Thread.currentThread().setName("我是主线程"); 

      //获取主函数线程的引用,并获取名字

   System.out.println(Thread.currentThread().

            getName());

休眠线程

       Thread.sleep(毫秒), 控制当前线程休眠若干毫秒

       new Thread() {

         public void run() {

            for(int i = 0; i < 10; i++) {

      System.out.println(getName() + "...aaaaaaaa");

                try {

                   //当前线程睡眠10毫秒

                   Thread.sleep(10);

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

     

      new Thread() {

         public void run() {

            for(int i = 0; i < 10; i++) {

                System.out.println(getName() + "...bb");

                try {

                   //当前线程睡眠10毫秒

                   Thread.sleep(10);

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

守护线程

         setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守  护线程都执行结束后, 自动退出

       Thread t1 = new Thread() {

         public void run() {

            for(int i = 0; i < 50; i++) {

         System.out.println(getName() + "...aaaaaa");

                try {

                   Thread.sleep(10);

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      };

     

      Threadt2 = new Thread() {

         public void run() {

            for(int i = 0; i < 5; i++) {

                System.out.println(getName() + "...bb");

                try {

                   Thread.sleep(10);

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      };

      //设置守护线程必须在thread.start()之前设置

      //不能把正在运行的常规线程设置为守护线程

      //传入truet1设置为守护线程,

      t1.setDaemon(true);

      t1.start();

      t2.start();

加入线程

         join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续

         join(int), 可以等待指定的毫秒之后继续

       final Thread t1 = new Thread() {

         public void run() {

            for(int i = 0; i < 50; i++) {

         System.out.println(getName() + "...aaaaaa");

               try {

                   Thread.sleep(10);

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      };

     

      Threadt2 = new Thread() {

         public void run() {

            for(int i = 0; i < 50; i++) {

                if(i == 2) {

                   try {

                   //插队,加入,直至t1线程全部执行完成

                   //t1.join();

                //加入,有固定的时间,过了固定时间,继续交替执行

                      t1.join(30);

                      Thread.sleep(10);

                   }catch (InterruptedException e) {

                      e.printStackTrace();

                   }

                }

                System.out.println(getName() + "...bb");

            }

         }

      };

      t1.start();

      t2.start();

礼让线程

       public class ThreadDemo3 {

 

   public static void main(String[] args) {

      new MThread().start();

      new MThread().start();

   }

}

class MThread extends Thread {

   @Override

   public void run() {

      for (int i = 0; i < 1000; i++) {

         if (i % 10 == 0) {

      //礼让线程,让出线程,但不一定有效果,线程执行由cup调度

            Thread.yield();

         }

         System.out.println(getName() + "...." + i);

      }

   }

}

设置线程的优先级

       setPriority()设置线程的优先级(效果不明显,因为线程调度是由cpu决定的)

       Thread t1 = new Thread() {

         @Override

         public void run() {

            for (int i = 0; i < 100; i++) {

         System.out.println(getName() + "...aaaaa");

            }

         }

      };

      Threadt2 = new Thread() {

         @Override

         public void run() {

            for (int i = 0; i < 100; i++) {

                System.out.println(getName() + "...bb");

            }

         }

      };

      // 设置线程优先级,最大是10,最小是1,默认是5

      //可以给int[1,10],也可以用Thread的常量

      // t1.setPriority(10);

      // t2.setPriority(1);

      t1.setPriority(Thread.MIN_PRIORITY);

      t2.setPriority(Thread.MAX_PRIORITY);

      t1.start();

      t2.start();

多线程同步代码块

         什么情况下需要同步

              a,当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程                         中CPU不要切换到其他线程工作. 这时就需要同步.

              b,如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行                         结束之前, 不会执行另外一段代码.

         同步代码块

              a,使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步               代码块

              b,多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

       public class ThreadDemo5 {

 

   public static void main(String[] args) {

      final Printer p = new Printer();

      new Thread() {

         @Override

         public void run() {

            while (true) {

                p.print1();

            }

         }

      }.start();

      new Thread() {

         @Override

         public void run() {

            while (true) {

                p.print2();

            }

         }

      }.start();

   }

}

class Demo {}

class Printer {

   Demo d = new Demo();

   public void print1() {

      // 锁对象可以是任意对象,但是被锁的代码需要保证是同一把锁,      //不能用匿名对象

      synchronized (d) {

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

      }

   }

   public void print2() {

      synchronized (d) {

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

      }

   }

}

多线程同步方法

       使用synchronized关键字修饰一个方法, 该方法中所有的代码都是同步的

       public class ThreadDemo6 {

 

   public static void main(String[] args) {

      final Printer2 p = new Printer2();

      new Thread() {

         @Override

         public void run() {

            while (true) {

                p.print1();

            }

         }

      }.start();

      new Thread() {

         @Override

         public void run() {

            while (true) {

                p.print2();

            }

         }

      }.start();

   }

}

class Printer2 {

   //非静态的同步方法的锁对象:this

   //静态的同步方法的锁对象不可能是this(静态方法是优选于类对象存在[静态方法比类要先加载]

   //静态的同步方法的锁对象:该类的字节码对象(.class文件)

   //同步方法只需在方法上添加synchronized关键字即可

   public static synchronized void print1() {

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

   }

   public static void print2() {

      synchronized (Printer2.class) {

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

      }

   }

}

线程安全问题

         多线程并发操作同一数据时, 就有可能出现线程安全问题,使用同步技术可以解      决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作

       使用继承Thread

       public class ThreadDemo7 {

 

   public static void main(String[] args) {

      TicketsSellert1 = new TicketsSeller();

      TicketsSellert2 = new TicketsSeller();

      TicketsSellert3 = new TicketsSeller();

      TicketsSellert4 = new TicketsSeller();

     

      t1.setName("窗口1");

      t2.setName("窗口2");

      t3.setName("窗口3");

      t4.setName("窗口4");

      t1.start();

      t2.start();

      t3.start();

      t4.start();

   }

 

}

class TicketsSeller extends Thread {

   private static int tickets = 100;

   //成员变量作为锁对象,必须保证所用的锁是同一个,不然无效

   static Object obj = new Object();

   public TicketsSeller() {

      super();

     

   }

   public TicketsSeller(String name) {

      super(name);

   }

   public void run() {

      while(true) {

//        synchronized(obj){

         synchronized(TicketsSeller.class) {

            if(tickets <= 0)

                break;

            try {

            //线程1,线程2,线程3,线程4

                Thread.sleep(10);

            }catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(getName() + "...这是第" + tickets-- + "号票");

         }

      }

   }

}

 

实现Runnable接口

public class ThreadDemo8 {

public static void main(String[] args) {

      MyTicketmt = new MyTicket();

      new Thread(mt,"窗口1").start();

      new Thread(mt,"窗口2").start();

      new Thread(mt,"窗口3").start();

      new Thread(mt,"窗口4").start();

   }

 

}

class MyTicket implements Runnable {

   private int tickets = 100;

   public void run() {

      while(true) {

//可以使用this,因为只创建了一个对象,也就是说共用了一个锁对象

//        synchronized(this){

         synchronized(MyTicket.class) {

            if(tickets <= 0)

                break;

            try {

                Thread.sleep(10);

            }catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(Thread.currentThread().getName()+ "...这是第" + tickets-- + "号票");

         }

      }

   }

}

死锁

         多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁,尽量    不要嵌套使用

       private static String s1 = "筷子左";

   private static String s2 = "筷子右";

   public static void main(String[] args) {

      new Thread() {

         public void run() {

            while(true) {

                synchronized(s1) {

                   System.out.println(getName() +

                      "...拿到" + s1 + "等待" + s2);

                   synchronized(s2) {

                      System.out.println(getName() +

                      "...拿到" + s2 + "开吃");

                   }

                }

            }

         }

      }.start();

     

      new Thread() {

         public void run() {

            while(true) {

                synchronized(s2) {

                   System.out.println(getName() +

                   "...拿到" + s2 + "等待" + s1);

                   synchronized(s1) {

                      System.out.println(getName() +

                   "...拿到" + s1 + "开吃");

                   }

                }

            }

         }

      }.start();

    }

以前的线程安全的类回顾

Vector,StringBuffer,Hashtable,Collections.synchroinzed(xxx)

         Vector是线程安全的,ArrayList是线程不安全的

         StringBuffer是线程安全的,StringBuilder是线程不安全的

        Hashtable是线程安全的,HashMap是线程不安全的

单例设计模式

       单例设计模式:保证类在内存中只有一个对象

         如何保证类在内存中只有一个对象呢?

              (1)控制类的创建,不让其他类来创建本类的对象。private

              (2)在本类中定义一个本类的对象。Singleton s;

              (3)提供公共的访问方式。  public static Singleton                                      getInstance(){returns}

       单例写法两种:

              (1)饿汉式 开发用这种方式

                     //饿汉式(不管用不用都创建对象)

      class Singleton{

      //1,私有构造器,其他类不能访问该构造方法

      privateSingleton(){}

      //2,创建本类对象

      private static Singleton s = new Singleton();

      //3,对外提供公共的访问方法

      public static Singleton getInstance(){

         return s;

      }

      public static void print(){

         System.out.println("------------");

      }

   }

              (2)懒汉式 面试写这种方式。多线程的问题?

              //懒汉式:单例的延迟加载模式(先声明不创建对象)

      class Singleton1 {

      //1,私有构造函数

      privateSingleton1(){}

      //2,声明一个本类的引用

      private static Singleton1 s;

      //3,对外提供公共的访问方法

      public static Singleton1 getInstance() {

         if(s == null)

//线程1等待,线程2等待(多线程访问会出现多次创建对象,有安全隐患)

         s = new Singleton1();

         return s;

      }

      public static void print() {

         System.out.println("11111111111");

      }

   }

      (3)第三种格式

              class Singleton2 {

         private Singleton2() {}

         //final是最终的意思,final修饰的变量不可以被更改

         public static final Singleton2 s =

         new Singleton2();

      }

 

       饿汉式和懒汉式的区别:

             1,饿汉式:空间换时间,懒汉式:时间换空间

              2,在多个线程访问时,饿汉式不会创建多个对象,而懒汉式有可能创建多个                       对象

多线程Runtime类

              //获取运行时对象(单列设置)

      Runtimer = Runtime.getRuntime();

      //执行字符串命名(关机)

      r.exec("shutdown -s -t 300");

      //取消执行命令

      r.exec("shutdown -a");

Timer计时器

       Timer:一种工具,线程用其安排以后在后台线程中执行的任务,可安排任   务执行一次,或者定期重复执行

public class ThreadDemo12 {

   public static void main(String[] args) throws InterruptedException {

      Timert = new Timer();

      //指定时间执行任务(年:当前年份-1900,月:0-11,日:1-31,时:24小时制,分:0-59,秒:0-59

      t.schedule(new MyTimerTask(), new Date(117, 2, 13, 18, 31,30));

      //从指定时间开始,隔3s时间后重复执行

      //第一个参数是执行的任务,第二个参数是执行的时间,第三个参数是过多长再时间重复

      t.schedule(new MyTimerTask(), new Date(117, 2, 13, 18, 31,30),3000);

      while(true){

         Thread.sleep(1000);

         System.out.println(new Date());

      }

   }

 

}

class MyTimerTask extends TimerTask{

   @Override

   public void run() {

      System.out.println("起床");

   } 

}

两个线程间的通信

         什么时候需要通信

              多个线程并发执行时, 在默认情况下CPU是随机切换线程的

              如果我们希望他们有规律的执行, 就可以使用通信, 例如每个线程执行一次                    打印

         怎么通信

              如果希望线程等待, 就调用wait()

              如果希望唤醒等待的线程, 就调用notify();

              这两个方法必须在同步代码中执行, 并且使用同步锁对象来调用

public class ThreadDemo01 {

   public static void main(String[] args) {

      final Printer p = new Printer();

      new Thread(){

         public void run() {

            while(true){

                try {

                   p.print1();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

      new Thread(){

         public void run() {

            while(true){

                try {

                   p.print2();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

   }

}

//等待唤醒机制

class Printer {

   private int flag = 1;

   public void print1() throws InterruptedException {

      synchronized (this) {

         if(flag!=1){

            //当前线程等待

            this.wait();

         }

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

         flag = 2;

         //随机唤醒单个等待的线程

         this.notify();

      }

   }

   public void print2() throws InterruptedException {

      synchronized (this) {

         if(flag!=2){

            this.wait();

         }

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

         flag = 1;

         this.notify();

      }

   }

}

三个或三个以上间的线程通信

         多个线程通信的问题

              notify()方法是随机唤醒一个线程

              notifyAll()方法是唤醒所有线程

              JDK5之前无法唤醒指定的一个线程

              如果多个线程之间通信, 需要使用notifyAll()通知所有线程, 用while来                反复判断条件

              下面是JDK1.5版本之前的处理方案

       public class ThreadDemo2 {

 

   public static void main(String[] args) {

      Printer1p = new Printer1();

      new Thread(){

         public void run() {

            while(true){

                try {

                   p.print1();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

      new Thread(){

         public void run() {

            while(true){

                try {

                   p.print2();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

 

      new Thread(){

         public void run() {

            while(true){

                try {

                   p.print3();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

 

 

   }

 

}

/**

 * 1,在同步代码块中,用哪个对象锁,就用哪个对象调用wait方法

 * 2,为什么wait方法和notify方法定义在Object类中?

 *    因为锁对象可以是任意对象,Object是所有的类的基类

 *    所以wait方法和notify方法需要定义在object这个类中

 * 3sleep方法和wait方法的区别?

 * asleep方法必须传入参数,参数就是时间,时间到了自动唤醒

 *    wait方法可以传入参数也可以不传入参数,传入参数就是在参数的时间结束后等待,不传入参数就是直接等待

 * bsleep在同步函数或同步代码块中不释放锁,wait方法在同步函数或者是同步代码块中释放锁

 *

 * @author LMD

 *

 */

 

// 等待唤醒机制

class Printer1 {

   private int flag = 1;

 

   public void print1() throws InterruptedException {

      synchronized (this) {

//if为啥换成while?因为wait方法在if(){wait}在哪里等待就在哪里起来,所以不会再进行像while那样的判断

         while (flag != 1) {

            // 当前线程等待

            this.wait();

         }

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

         flag = 2;

         // 随机唤醒单个等待的线程

//        this.notify();

         this.notifyAll();

      }

   }

 

   public void print2() throws InterruptedException {

      synchronized (this) {

         while (flag != 2) {

            this.wait();

         }

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

         flag = 3;

//        this.notify();

         this.notifyAll();

      }

   }

 

   public void print3() throws InterruptedException {

      synchronized (this) {

         while (flag != 3) {//while是循环判断,每次都会判断标记

            this.wait();

         }

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("");

         System.out.print("\r\n");

         flag = 1;

//        this.notify();

         this.notifyAll();

      }

   }

}

JDK1.5的新特性互斥锁

         同步:使用ReentrantLock类的lock()和unlock()方法进行同步

         通信:

         1,使用ReentrantLock类的newCondition()方法可以获取Condition对象

         2,需要等待的时候使用Condition的await()方法, 唤醒时用signal()方法

         3,不同的线程使用不同的Condition, 这样就能区分唤醒的时候找哪个线程了

public classReentrantLockDemo {

 

   public static void main(String[] args) {

      Printer2p = new Printer2();

      new Thread() {

         public void run() {

            while (true) {

                try {

                   p.print1();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

      new Thread() {

         public void run() {

            while (true) {

                try {

                   p.print2();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

      new Thread() {

         public void run() {

            while (true) {

                try {

                   p.print3();

                }catch (InterruptedException e) {

                   e.printStackTrace();

                }

            }

         }

      }.start();

 

   }

 

}

 

class Printer2 {

   private ReentrantLock r = new ReentrantLock();

   // 创建监视器

   private Condition c1 = r.newCondition();

   private Condition c2 = r.newCondition();

   private Condition c3 = r.newCondition();

   private int flag = 1;

 

   public void print1() throws InterruptedException {

      // 获取锁

      r.lock();

      // 每次只唤醒一个线程,所以不用进行循环判断

      if (flag != 1) {

         c1.await();

      }

      System.out.print("");

      System.out.print("");

      System.out.print("");

      System.out.print("");

      System.out.print("\r\n");

      flag = 2;

      c2.signal();

      // 释放锁

      r.unlock();

   }

 

   public void print2() throws InterruptedException {

      // 获取锁

      r.lock();

      if (flag != 2) {

         c2.await();

      }

      System.out.print("");

      System.out.print("");

      System.out.print("");

      System.out.print("");

      System.out.print("\r\n");

      flag = 3;

      c3.signal();

      // 释放锁

      r.unlock();

   }

 

   public void print3() throws InterruptedException {

      // 获取锁

      r.lock();

      if (flag != 3) {

         c3.await();

      }

      System.out.print("");

      System.out.print("");

      System.out.print("");

      System.out.print("");

      System.out.print("\r\n");

      flag = 1;

      c1.signal();

      // 释放锁

      r.unlock();

   }

}

线程组的概述和使用

         线程组概述

         a,Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,                    Java允许程序直接对线程组进行控制。

         b,默认情况下,所有的线程都属于主线程组。

         c,public final ThreadGroup getThreadGroup()//通过线程对象获取                   他所属于的组

         d,public final String getName()//通过线程组对象获取他组的名字

         e,我们也可以给线程设置分组

                     1,ThreadGroup(Stringname) 创建线程组对象并给其赋值名字

                     2,创建线程对象

                     3,Thread(ThreadGroup?group,Runnable?target,                                              String?name)

                     4,设置整组的优先级或者守护线程

代码示例:

public class ThreadGroupDemo{

 

   public static void main(String[] args) {

//     demo1();

      //创建新的线程组

      ThreadGrouptg = new ThreadGroup("我是一个新的线程组");

      //创建Runnable的子类对象

      MyRunnablemr = new MyRunnable();

      //将线程t1放在线程组中

      Threadt1 = new Thread(tg,mr,"张三");

      //将线程t1放在线程组中

      Threadt2 = new Thread(tg,mr,"李四");

      //获取组名

      System.out.println(t1.getThreadGroup().getName());

   System.out.println(t2.getThreadGroup().getName());

      //将整组变成守护线程

      tg.setDaemon(true);

   }

   public static void demo1() {

      MyRunnablemr = new MyRunnable();

      Threadt1 = new Thread(mr,"张三");

      Threadt2 = new Thread(mr,"李四");

      //获取线程组

      ThreadGrouptg1 = t1.getThreadGroup();

      ThreadGrouptg2 = t2.getThreadGroup();

      //默认是主线程

      System.out.println(tg1.getName());

      System.out.println(tg2.getName());

   }

 

}

class MyRunnable implements Runnable{

   @Override

   public void run() {

      for (int i = 0; i < 1000; i++) {   System.out.println(Thread.currentThread().

      getName()+"....."+i);

      }

   }

}

线程的五种状态

线程池的概述和使用

         线程池概述:程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统  进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存      期很短的线程时,更应该考虑使用线程池。线程池里的每一个线程代码结束后,    并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。在   JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程    池

         内置线程池的使用概述

              1,JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法

              2,public staticExecutorService newFixedThreadPool(int                         nThreads)创建一个可重用固定线程数的线程池

              3,public staticExecutorService newSingleThreadExecutor()

              4,这些方法的返回值是ExecutorService对象,该对象表示一个线程池,                       可以执行Runnable对象或者Callable对象代表的线程。它提供了如下                       方法

              5,Future<?>submit(Runnable task)

              6,<T>Future<T> submit(Callable<T> task)

         使用步骤:

              创建线程池对象

              创建Runnable实例

              提交Runnable实例

              关闭线程池

程序示例:

public class ThreadDemo3 {

   public static void main(String[] args) {

      // 创建线程池

      ExecutorServicepool = Executors.newFixedThreadPool(2);

      // 将线程放进线程池并执行

      pool.submit(new MyRunnable1());

      pool.submit(new MyRunnable1());

      // 关闭线程池

      pool.shutdown();

 

   }

}

 

class MyRunnable1 implements Runnable {

   @Override

   public void run() {

      for (int i = 0; i < 1000; i++) {

         System.out.println(Thread.currentThread().

         getName()+ "....." + i);

      }

   }

}

多线程程序实现的方式3

       提交的是Callable(其他两种是:继承Thread类,实现Runnable接口)

       public class ThreadCallable {

 

   public static void main(String[] args) throws InterruptedException, ExecutionException {

      //创建线程池

      ExecutorServicepool = Executors.newFixedThreadPool(2);

      //Callable的子类提交到线程池中,Future接收计算的结果

      Future<Integer>f1 =pool.submit(new MyCallable(100));

      Future<Integer>f2 = pool.submit(new MyCallable(50));

      System.out.println(f1.get());

      System.out.println(f2.get());

      pool.shutdown();

   }

 

}

 

class MyCallable implements Callable<Integer> {

   private int num;

 

   public MyCallable(int num) {

      this.num = num;

   }

 

   @Override

   public Integer call() throws Exception {

      int sum = 0;

      for (int i = 1; i <= num; i++) {

         sum += i;

      }

      return sum;

   }

}

         多线程程序实现的方式3的好处和弊端

              好处:可以有返回值,可以抛出异常

              弊端:代码比较复杂,所以一般不用

简单工厂模式概述和使用

         简单工厂模式概述:又叫静态工厂方法模式,它定义一个具体的工厂类负责创建                一些类的实例

         优点:客户端不需要在负责对象的创建,从而明确了各个类的职责

         缺点:这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对                象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护

              public class AnimalFactory {

   //  public static Dog creatDog(){

   //     return new Dog();

   //  }

   //  public static Cat creatCat(){

   //     return new Cat();

   //  }

   //上面方法定义很多,复用性太差

   public static AnimalcreateAnimal(String name){

      if("Dog".equals(name)){

         return new Dog();

      }else if("Cat".equals(name)){

         return new Cat();

      }else{

         return null;

      }

   }

}

工厂方法模式的概述和使用

         工厂方法模式概述:工厂方法模式中抽象工厂类负责定义创建对象的接口,具体                       对象的创建工作由继承抽象工厂的具体类实现。

         优点:客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的                       对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的                          代码,后期维护容易,增强了系统的扩展性

         缺点:需要额外的编写代码,增加了工作量

         动物抽象类:public abstract class Animal{

                                   public abstract void eat(); }

         工厂接口:public interfaceFactory {

                                   publicabstract Animal createAnimal();}

         具体狗类:public class Dogextends Animal {}

         具体猫类:public class Catextends Animal {}

         (开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比 较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。      发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具    体工厂)

         狗工厂:public class DogFactory implements Factory {

                     public Animal createAnimal() {…}

                      }

         猫工厂:public class CatFactory implements Factory {

                     public Animal createAnimal() {…}

                      }

         具体使用

              DogFactory df = new DogFactory();

              df.eat();

如何创建一个窗口并显示

         GraphicalUser Interface(图形用户接口)

       //构造函数传入的是窗体title

      Frame  f = new Frame("my window");

      //设置布局管理器

      f.setLayout(new FlowLayout());

      //设置窗体大小

      f.setSize(500,400);

      //设置窗体出现在屏幕的位置

      f.setLocation(300,200);

      //设置图标

      f.setIconImage(Toolkit.getDefaultToolkit().

         createImage("img.jpg"));

      //设置窗体可见

      f.setVisible(true);

布局管理器

         FlowLayout(流式布局管理器)

              从左到右的顺序排列; Panel默认的布局管理器。

         BorderLayout(边界布局管理器)

              东,南,西,北,中;Frame默认的布局管理器

         GridLayout(网格布局管理器):规则的矩阵

         CardLayout(卡片布局管理器):选项卡

         GridBagLayout(网格包布局管理器):非规则的矩阵

 

       Frame f = new Frame("my window");

      Buttonb1 = new Button("按钮1");

      f.add(b1);

      //设置布局管理器

      f.setLayout(new FlowLayout());

      f.setVisible(true);

窗体监听

              Frame f = new Frame("我的窗体");

         //事件源是窗体,把监听器注册到事件源上

         //事件对象传递给监听器

       f.addWindowListener(new WindowAdapter() {

         @Override

         public voidwindowClosing(WindowEvent e) {

             //退出虚拟机,关闭窗口

            System.exit(0);

         }

      });

 

鼠标监听

   Buttonb1 = new Button("按钮1");

      b1.addMouseListener(new MouseAdapter() {

         //鼠标释放

         @Override

         public voidmouseReleased(MouseEvent e) {

            //退出虚拟机,关闭窗口

            System.exit(0);

         }

        

      });

键盘监听和键盘事件

       b1.addKeyListener(new KeyAdapter() {

         @Override

         public voidkeyReleased(KeyEvent e) {

            //获取键盘按下的键值code,空格退出

            if(e.getKeyCode()==KeyEvent.VK_SPACE)

            System.exit(0);

         }

      });

动作监听

       //添加动作监听,应用场景:暂停视频和播放视频

      b1.addActionListener(new ActionListener() {

        

         @Override

         public voidactionPerformed(ActionEvent e) {

            System.exit(0);

         }

      });

    事件处理

              事件: 用户的一个操作

              事件源: 被操作的组件

              监听器: 一个自定义类的对象, 实现了监听器接口, 包含事件处理方法,把监                    听器添加在事件源上, 当事件发生的时候虚拟机就会自动调用监听器中              的事件处理方法

 

适配器设计模式

         什么是适配器

              1,在使用监听器的时候, 需要定义一个类事件监听器接口.

              2,通常接口中有多个方法, 而程序中不一定所有的都用到, 但又必须重写,                            这很繁琐.

              3,适配器简化了这些操作, 我们定义监听器时只要继承适配器, 然后重写需                         要的方法即可.

         适配器原理

              1,适配器就是一个类, 实现了监听器接口, 所有抽象方法都重写了, 但是方                          法全是空的.

              2,适配器类需要定义成抽象的,因为创建该类对象,调用空方法是没有意义的

              3,目的就是为了简化程序员的操作, 定义监听器时继承适配器, 只重写需要                         的方法就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值